summaryrefslogtreecommitdiff
path: root/npc
diff options
context:
space:
mode:
Diffstat (limited to 'npc')
-rw-r--r--npc/000-0-0/_import.txt5
-rw-r--r--npc/000-0-0/mapflags.txt1
-rw-r--r--npc/000-0-0/q'onan.txt14
-rw-r--r--npc/000-0-0/sailors.txt92
-rw-r--r--npc/000-0-1/_import.txt4
-rw-r--r--npc/000-0-1/mapflags.txt1
-rw-r--r--npc/000-0-1/narrator.txt180
-rw-r--r--npc/000-0/_import.txt4
-rw-r--r--npc/000-0/mapflags.txt1
-rw-r--r--npc/000-0/sailors.txt92
-rw-r--r--npc/000-1/_import.txt24
-rw-r--r--npc/000-1/_mobs.txt38
-rw-r--r--npc/000-1/_warps.txt3
-rw-r--r--npc/000-1/ale.txt109
-rw-r--r--npc/000-1/astapolos.txt165
-rw-r--r--npc/000-1/boss.txt43
-rw-r--r--npc/000-1/chest.txt65
-rw-r--r--npc/000-1/couwan.txt94
-rw-r--r--npc/000-1/darlin.txt148
-rw-r--r--npc/000-1/fexil.txt43
-rw-r--r--npc/000-1/gugli.txt248
-rw-r--r--npc/000-1/gulukan.txt169
-rw-r--r--npc/000-1/jalad.txt130
-rw-r--r--npc/000-1/lean.txt73
-rw-r--r--npc/000-1/mapflags.txt1
-rw-r--r--npc/000-1/maxe.txt111
-rw-r--r--npc/000-1/muller.txt131
-rw-r--r--npc/000-1/panels.txt54
-rw-r--r--npc/000-1/sapartan.txt101
-rw-r--r--npc/000-1/shop.txt32
-rw-r--r--npc/000-1/silvio.txt185
-rw-r--r--npc/000-1/tarlan.txt64
-rw-r--r--npc/000-1/tibbo.txt122
-rw-r--r--npc/000-2-0/_import.txt8
-rw-r--r--npc/000-2-0/_warps.txt3
-rw-r--r--npc/000-2-0/billybons.txt95
-rw-r--r--npc/000-2-0/doors.txt85
-rw-r--r--npc/000-2-0/julia.txt289
-rw-r--r--npc/000-2-0/mapflags.txt1
-rw-r--r--npc/000-2-0/note.txt27
-rw-r--r--npc/000-2-1/_import.txt17
-rw-r--r--npc/000-2-1/_mobs.txt3
-rw-r--r--npc/000-2-1/_savepoints.txt54
-rw-r--r--npc/000-2-1/_warps.txt3
-rw-r--r--npc/000-2-1/alige.txt321
-rw-r--r--npc/000-2-1/arpan.txt304
-rw-r--r--npc/000-2-1/chefgado.txt226
-rw-r--r--npc/000-2-1/chest.txt72
-rw-r--r--npc/000-2-1/dan.txt93
-rw-r--r--npc/000-2-1/devis.txt16
-rw-r--r--npc/000-2-1/hammock.txt125
-rw-r--r--npc/000-2-1/knife.txt47
-rw-r--r--npc/000-2-1/mapflags.txt1
-rw-r--r--npc/000-2-1/peter.txt302
-rw-r--r--npc/000-2-1/q'onan.txt15
-rw-r--r--npc/000-2-1/story_save.txt30
-rw-r--r--npc/000-2-2/_import.txt5
-rw-r--r--npc/000-2-2/doors.txt75
-rw-r--r--npc/000-2-2/mapflags.txt1
-rw-r--r--npc/000-2-2/ratto.txt98
-rw-r--r--npc/000-2-3/_import.txt10
-rw-r--r--npc/000-2-3/_warps.txt3
-rw-r--r--npc/000-2-3/box.txt112
-rw-r--r--npc/000-2-3/elmo.txt66
-rw-r--r--npc/000-2-3/hammock.txt17
-rw-r--r--npc/000-2-3/mapflags.txt1
-rw-r--r--npc/000-2-3/nard.txt341
-rw-r--r--npc/000-2-3/piourocket.txt29
-rw-r--r--npc/000-2-3/sailors.txt47
-rw-r--r--npc/000-2-4/_import.txt6
-rw-r--r--npc/000-2-4/_mobs.txt3
-rw-r--r--npc/000-2-4/_warps.txt3
-rw-r--r--npc/000-2-4/alige.txt38
-rw-r--r--npc/000-2-4/mapflags.txt1
-rw-r--r--npc/001-1/_import.txt45
-rw-r--r--npc/001-1/_mobs.txt32
-rw-r--r--npc/001-1/_warps.txt445
-rw-r--r--npc/001-1/artaxe.txt18
-rw-r--r--npc/001-1/beuss.txt27
-rw-r--r--npc/001-1/calypsan.txt104
-rw-r--r--npc/001-1/carmie.txt68
-rw-r--r--npc/001-1/chelios.txt135
-rw-r--r--npc/001-1/cookiemaster.txt256
-rw-r--r--npc/001-1/devis.txt99
-rw-r--r--npc/001-1/doors.txt61
-rw-r--r--npc/001-1/elmo.txt19
-rw-r--r--npc/001-1/enora.txt461
-rw-r--r--npc/001-1/eugene.txt82
-rw-r--r--npc/001-1/fexil.txt143
-rw-r--r--npc/001-1/flags.txt17
-rw-r--r--npc/001-1/flyingpiou.txt160
-rw-r--r--npc/001-1/harbours.txt84
-rw-r--r--npc/001-1/juscare.txt92
-rw-r--r--npc/001-1/katja.txt128
-rw-r--r--npc/001-1/koga.txt45
-rw-r--r--npc/001-1/lucas.txt18
-rw-r--r--npc/001-1/manhole.txt88
-rw-r--r--npc/001-1/mapflags.txt1
-rw-r--r--npc/001-1/marine.txt17
-rw-r--r--npc/001-1/merlin.txt24
-rw-r--r--npc/001-1/mouboo.txt61
-rw-r--r--npc/001-1/nalkri.txt59
-rw-r--r--npc/001-1/panels.txt57
-rw-r--r--npc/001-1/pious.txt15
-rw-r--r--npc/001-1/qonan.txt113
-rw-r--r--npc/001-1/qpid.txt169
-rw-r--r--npc/001-1/rowboat.txt69
-rw-r--r--npc/001-1/rowboathelper.txt141
-rw-r--r--npc/001-1/rumly.txt225
-rw-r--r--npc/001-1/salem.txt219
-rw-r--r--npc/001-1/shop.txt298
-rw-r--r--npc/001-1/sign.txt168
-rw-r--r--npc/001-1/sophialla.txt88
-rw-r--r--npc/001-1/taree.txt20
-rw-r--r--npc/001-1/treeleaf.txt22
-rw-r--r--npc/001-1/trees.txt220
-rw-r--r--npc/001-1/wateranimation.txt23
-rw-r--r--npc/001-1/xilaxa.txt50
-rw-r--r--npc/001-2-0/_import.txt6
-rw-r--r--npc/001-2-0/_warps.txt4
-rw-r--r--npc/001-2-0/mapflags.txt1
-rw-r--r--npc/001-2-0/resa.txt79
-rw-r--r--npc/001-2-0/shop.txt34
-rw-r--r--npc/001-2-1/_import.txt5
-rw-r--r--npc/001-2-1/_savepoints.txt15
-rw-r--r--npc/001-2-1/_warps.txt3
-rw-r--r--npc/001-2-1/mapflags.txt1
-rw-r--r--npc/001-2-10/_import.txt5
-rw-r--r--npc/001-2-10/_savepoints.txt15
-rw-r--r--npc/001-2-10/_warps.txt4
-rw-r--r--npc/001-2-10/mapflags.txt1
-rw-r--r--npc/001-2-11/_import.txt6
-rw-r--r--npc/001-2-11/_savepoints.txt15
-rw-r--r--npc/001-2-11/_warps.txt3
-rw-r--r--npc/001-2-11/mapflags.txt1
-rw-r--r--npc/001-2-11/mona.txt170
-rw-r--r--npc/001-2-12/_import.txt5
-rw-r--r--npc/001-2-12/_warps.txt5
-rw-r--r--npc/001-2-12/mapflags.txt1
-rw-r--r--npc/001-2-12/oscar.txt144
-rw-r--r--npc/001-2-13/_import.txt5
-rw-r--r--npc/001-2-13/_savepoints.txt15
-rw-r--r--npc/001-2-13/_warps.txt3
-rw-r--r--npc/001-2-13/mapflags.txt1
-rw-r--r--npc/001-2-14/_import.txt4
-rw-r--r--npc/001-2-14/_warps.txt3
-rw-r--r--npc/001-2-14/mapflags.txt1
-rw-r--r--npc/001-2-15/_import.txt5
-rw-r--r--npc/001-2-15/_savepoints.txt15
-rw-r--r--npc/001-2-15/_warps.txt3
-rw-r--r--npc/001-2-15/mapflags.txt1
-rw-r--r--npc/001-2-16/_import.txt4
-rw-r--r--npc/001-2-16/_warps.txt4
-rw-r--r--npc/001-2-16/mapflags.txt1
-rw-r--r--npc/001-2-17/_import.txt4
-rw-r--r--npc/001-2-17/_warps.txt3
-rw-r--r--npc/001-2-17/mapflags.txt1
-rw-r--r--npc/001-2-18/_import.txt4
-rw-r--r--npc/001-2-18/_warps.txt4
-rw-r--r--npc/001-2-18/mapflags.txt1
-rw-r--r--npc/001-2-19/_import.txt5
-rw-r--r--npc/001-2-19/_warps.txt51
-rw-r--r--npc/001-2-19/lloyd.txt249
-rw-r--r--npc/001-2-19/mapflags.txt1
-rw-r--r--npc/001-2-2/_import.txt5
-rw-r--r--npc/001-2-2/_warps.txt4
-rw-r--r--npc/001-2-2/mapflags.txt1
-rw-r--r--npc/001-2-2/moon.txt215
-rw-r--r--npc/001-2-20/_import.txt4
-rw-r--r--npc/001-2-20/_warps.txt26
-rw-r--r--npc/001-2-20/mapflags.txt1
-rw-r--r--npc/001-2-21/_import.txt6
-rw-r--r--npc/001-2-21/_warps.txt5
-rw-r--r--npc/001-2-21/julia.txt140
-rw-r--r--npc/001-2-21/mapflags.txt1
-rw-r--r--npc/001-2-21/note.txt27
-rw-r--r--npc/001-2-22/_import.txt13
-rw-r--r--npc/001-2-22/_mobs.txt3
-rw-r--r--npc/001-2-22/_savepoints.txt67
-rw-r--r--npc/001-2-22/_warps.txt3
-rw-r--r--npc/001-2-22/alige.txt325
-rw-r--r--npc/001-2-22/chefgado.txt112
-rw-r--r--npc/001-2-22/chest.txt49
-rw-r--r--npc/001-2-22/hammock.txt137
-rw-r--r--npc/001-2-22/knife.txt47
-rw-r--r--npc/001-2-22/mapflags.txt1
-rw-r--r--npc/001-2-22/note.txt33
-rw-r--r--npc/001-2-22/peter.txt302
-rw-r--r--npc/001-2-23/_import.txt6
-rw-r--r--npc/001-2-23/_warps.txt3
-rw-r--r--npc/001-2-23/doors.txt75
-rw-r--r--npc/001-2-23/mapflags.txt1
-rw-r--r--npc/001-2-23/ratto.txt98
-rw-r--r--npc/001-2-24/_import.txt7
-rw-r--r--npc/001-2-24/_warps.txt3
-rw-r--r--npc/001-2-24/hammock.txt17
-rw-r--r--npc/001-2-24/mapflags.txt1
-rw-r--r--npc/001-2-24/nard.txt93
-rw-r--r--npc/001-2-24/piourocket.txt9
-rw-r--r--npc/001-2-25/_import.txt5
-rw-r--r--npc/001-2-25/_mobs.txt3
-rw-r--r--npc/001-2-25/_warps.txt3
-rw-r--r--npc/001-2-25/mapflags.txt1
-rw-r--r--npc/001-2-26/_import.txt6
-rw-r--r--npc/001-2-26/_warps.txt3
-rw-r--r--npc/001-2-26/flask.txt21
-rw-r--r--npc/001-2-26/ivan.txt85
-rw-r--r--npc/001-2-26/mapflags.txt1
-rw-r--r--npc/001-2-27/_import.txt8
-rw-r--r--npc/001-2-27/_warps.txt3
-rw-r--r--npc/001-2-27/don.txt112
-rw-r--r--npc/001-2-27/kaylo.txt43
-rw-r--r--npc/001-2-27/lydon.txt36
-rw-r--r--npc/001-2-27/mapflags.txt1
-rw-r--r--npc/001-2-27/shop.txt62
-rw-r--r--npc/001-2-28/_import.txt8
-rw-r--r--npc/001-2-28/_warps.txt5
-rw-r--r--npc/001-2-28/jenna.txt78
-rw-r--r--npc/001-2-28/mapflags.txt1
-rw-r--r--npc/001-2-28/note.txt43
-rw-r--r--npc/001-2-28/plush.txt127
-rw-r--r--npc/001-2-28/shop.txt24
-rw-r--r--npc/001-2-29/_import.txt5
-rw-r--r--npc/001-2-29/_savepoints.txt54
-rw-r--r--npc/001-2-29/_warps.txt4
-rw-r--r--npc/001-2-29/mapflags.txt1
-rw-r--r--npc/001-2-3/_import.txt5
-rw-r--r--npc/001-2-3/_savepoints.txt15
-rw-r--r--npc/001-2-3/_warps.txt3
-rw-r--r--npc/001-2-3/mapflags.txt1
-rw-r--r--npc/001-2-30/_import.txt5
-rw-r--r--npc/001-2-30/_mobs.txt3
-rw-r--r--npc/001-2-30/_warps.txt3
-rw-r--r--npc/001-2-30/mapflags.txt1
-rw-r--r--npc/001-2-31/_import.txt4
-rw-r--r--npc/001-2-31/_warps.txt4
-rw-r--r--npc/001-2-31/mapflags.txt1
-rw-r--r--npc/001-2-32/_import.txt6
-rw-r--r--npc/001-2-32/_warps.txt3
-rw-r--r--npc/001-2-32/doors.txt38
-rw-r--r--npc/001-2-32/mapflags.txt1
-rw-r--r--npc/001-2-32/serena.txt215
-rw-r--r--npc/001-2-33/_import.txt6
-rw-r--r--npc/001-2-33/_warps.txt53
-rw-r--r--npc/001-2-33/lozerk.txt195
-rw-r--r--npc/001-2-33/mapflags.txt3
-rw-r--r--npc/001-2-33/triggers.txt102
-rw-r--r--npc/001-2-34/_import.txt6
-rw-r--r--npc/001-2-34/_warps.txt3
-rw-r--r--npc/001-2-34/doors.txt29
-rw-r--r--npc/001-2-34/mapflags.txt1
-rw-r--r--npc/001-2-34/samantha.txt54
-rw-r--r--npc/001-2-35/_import.txt4
-rw-r--r--npc/001-2-35/doors.txt19
-rw-r--r--npc/001-2-35/mapflags.txt2
-rw-r--r--npc/001-2-36/_import.txt5
-rw-r--r--npc/001-2-36/_warps.txt3
-rw-r--r--npc/001-2-36/hector.txt460
-rw-r--r--npc/001-2-36/mapflags.txt1
-rw-r--r--npc/001-2-37/_import.txt6
-rw-r--r--npc/001-2-37/_savepoints.txt54
-rw-r--r--npc/001-2-37/_warps.txt4
-rw-r--r--npc/001-2-37/hammock.txt106
-rw-r--r--npc/001-2-37/mapflags.txt1
-rw-r--r--npc/001-2-38/_import.txt6
-rw-r--r--npc/001-2-38/_savepoints.txt54
-rw-r--r--npc/001-2-38/_warps.txt4
-rw-r--r--npc/001-2-38/hammock.txt106
-rw-r--r--npc/001-2-38/mapflags.txt1
-rw-r--r--npc/001-2-39/_import.txt5
-rw-r--r--npc/001-2-39/_warps.txt4
-rw-r--r--npc/001-2-39/mapflags.txt1
-rw-r--r--npc/001-2-39/qanon.txt131
-rw-r--r--npc/001-2-4/_import.txt7
-rw-r--r--npc/001-2-4/_warps.txt27
-rw-r--r--npc/001-2-4/books.txt102
-rw-r--r--npc/001-2-4/mapflags.txt1
-rw-r--r--npc/001-2-4/robin.txt64
-rw-r--r--npc/001-2-4/terry.txt15
-rw-r--r--npc/001-2-40/_import.txt5
-rw-r--r--npc/001-2-40/_warps.txt5
-rw-r--r--npc/001-2-40/mapflags.txt1
-rw-r--r--npc/001-2-40/trozz.txt66
-rw-r--r--npc/001-2-41/_import.txt5
-rw-r--r--npc/001-2-41/_warps.txt3
-rw-r--r--npc/001-2-41/edouard.txt175
-rw-r--r--npc/001-2-41/mapflags.txt1
-rw-r--r--npc/001-2-42/_import.txt3
-rw-r--r--npc/001-2-42/_warps.txt3
-rw-r--r--npc/001-2-43/_import.txt5
-rw-r--r--npc/001-2-43/_warps.txt3
-rw-r--r--npc/001-2-43/core.txt147
-rw-r--r--npc/001-2-43/mapflags.txt1
-rw-r--r--npc/001-2-5/_import.txt6
-rw-r--r--npc/001-2-5/_warps.txt3
-rw-r--r--npc/001-2-5/books.txt33
-rw-r--r--npc/001-2-5/mapflags.txt1
-rw-r--r--npc/001-2-5/tutorial.txt266
-rw-r--r--npc/001-2-6/_import.txt8
-rw-r--r--npc/001-2-6/_warps.txt3
-rw-r--r--npc/001-2-6/books.txt345
-rw-r--r--npc/001-2-6/christopher.txt68
-rw-r--r--npc/001-2-6/dolfina.txt20
-rw-r--r--npc/001-2-6/leonard.txt88
-rw-r--r--npc/001-2-6/mapflags.txt1
-rw-r--r--npc/001-2-7/_import.txt4
-rw-r--r--npc/001-2-7/_warps.txt5
-rw-r--r--npc/001-2-7/mapflags.txt1
-rw-r--r--npc/001-2-8/_import.txt5
-rw-r--r--npc/001-2-8/_warps.txt3
-rw-r--r--npc/001-2-8/doors.txt59
-rw-r--r--npc/001-2-8/mapflags.txt1
-rw-r--r--npc/001-2-9/_import.txt5
-rw-r--r--npc/001-2-9/_warps.txt3
-rw-r--r--npc/001-2-9/janus.txt170
-rw-r--r--npc/001-2-9/mapflags.txt1
-rw-r--r--npc/001-3-0/_import.txt6
-rw-r--r--npc/001-3-0/_mobs.txt39
-rw-r--r--npc/001-3-0/_warps.txt8
-rw-r--r--npc/001-3-0/gates.txt201
-rw-r--r--npc/001-3-0/mundane.txt208
-rw-r--r--npc/001-3-1/_import.txt5
-rw-r--r--npc/001-3-1/_mobs.txt8
-rw-r--r--npc/001-3-1/_warps.txt4
-rw-r--r--npc/001-3-1/gates.txt66
-rw-r--r--npc/001-3-2/_import.txt5
-rw-r--r--npc/001-3-2/_warps.txt3
-rw-r--r--npc/001-3-2/henry.txt374
-rw-r--r--npc/001-3-2/smuggler.txt84
-rw-r--r--npc/008-1-1/_import.txt11
-rw-r--r--npc/008-1-1/_mobs.txt38
-rw-r--r--npc/008-1-1/_warps.txt5
-rw-r--r--npc/008-1-1/cutscene.txt180
-rw-r--r--npc/008-1-1/galimatia.txt431
-rw-r--r--npc/008-1-1/hal.txt131
-rw-r--r--npc/008-1-1/koga.txt34
-rw-r--r--npc/008-1-1/morcant.txt63
-rw-r--r--npc/008-1-1/sign.txt22
-rw-r--r--npc/008-1-1/soldiers.txt31
-rw-r--r--npc/008-1-2/_import.txt4
-rw-r--r--npc/008-1-2/_warps.txt4
-rw-r--r--npc/008-1-2/sign.txt31
-rw-r--r--npc/008-1/4144.txt90
-rw-r--r--npc/008-1/_import.txt29
-rw-r--r--npc/008-1/_mobs.txt124
-rw-r--r--npc/008-1/_warps.txt33
-rw-r--r--npc/008-1/auldsbel.txt53
-rw-r--r--npc/008-1/banu.txt20
-rw-r--r--npc/008-1/blossom.txt77
-rw-r--r--npc/008-1/confused-tree.txt972
-rw-r--r--npc/008-1/crane.txt92
-rw-r--r--npc/008-1/doors.txt43
-rw-r--r--npc/008-1/hinnak.txt354
-rw-r--r--npc/008-1/jack.txt314
-rw-r--r--npc/008-1/mapflags.txt1
-rw-r--r--npc/008-1/marine.txt17
-rw-r--r--npc/008-1/mikhail.txt123
-rw-r--r--npc/008-1/milly.txt119
-rw-r--r--npc/008-1/old-man.txt89
-rw-r--r--npc/008-1/old-woman.txt136
-rw-r--r--npc/008-1/oscar.txt19
-rw-r--r--npc/008-1/rossy.txt391
-rw-r--r--npc/008-1/sabine.txt63
-rw-r--r--npc/008-1/sergeant-ryan.txt71
-rw-r--r--npc/008-1/shop.txt50
-rw-r--r--npc/008-1/sign.txt45
-rw-r--r--npc/008-1/snarfles.txt97
-rw-r--r--npc/008-1/soul-menhir.txt9
-rw-r--r--npc/008-1/voltain.txt18
-rw-r--r--npc/008-1/wateranimation.txt21
-rw-r--r--npc/008-2-0/_import.txt6
-rw-r--r--npc/008-2-0/_savepoints.txt15
-rw-r--r--npc/008-2-0/_warps.txt4
-rw-r--r--npc/008-2-0/celestia.txt19
-rw-r--r--npc/008-2-0/mapflags.txt1
-rw-r--r--npc/008-2-1/_import.txt9
-rw-r--r--npc/008-2-1/_savepoints.txt15
-rw-r--r--npc/008-2-1/_warps.txt4
-rw-r--r--npc/008-2-1/generalstore.txt19
-rw-r--r--npc/008-2-1/inspector.txt190
-rw-r--r--npc/008-2-1/mapflags.txt1
-rw-r--r--npc/008-2-1/richard.txt62
-rw-r--r--npc/008-2-1/selim.txt22
-rw-r--r--npc/008-2-10/_import.txt5
-rw-r--r--npc/008-2-10/_warps.txt4
-rw-r--r--npc/008-2-10/airlia.txt33
-rw-r--r--npc/008-2-10/mapflags.txt1
-rw-r--r--npc/008-2-11/_import.txt5
-rw-r--r--npc/008-2-11/_savepoints.txt28
-rw-r--r--npc/008-2-11/_warps.txt3
-rw-r--r--npc/008-2-11/mapflags.txt1
-rw-r--r--npc/008-2-12/_import.txt5
-rw-r--r--npc/008-2-12/_warps.txt4
-rw-r--r--npc/008-2-12/mapflags.txt1
-rw-r--r--npc/008-2-12/nurse.txt175
-rw-r--r--npc/008-2-13/_import.txt6
-rw-r--r--npc/008-2-13/_savepoints.txt54
-rw-r--r--npc/008-2-13/_warps.txt4
-rw-r--r--npc/008-2-13/lena.txt270
-rw-r--r--npc/008-2-13/mapflags.txt1
-rw-r--r--npc/008-2-14/_import.txt6
-rw-r--r--npc/008-2-14/_savepoints.txt15
-rw-r--r--npc/008-2-14/_warps.txt3
-rw-r--r--npc/008-2-14/doctor.txt114
-rw-r--r--npc/008-2-14/mapflags.txt1
-rw-r--r--npc/008-2-15/_import.txt3
-rw-r--r--npc/008-2-15/_warps.txt3
-rw-r--r--npc/008-2-16/_import.txt5
-rw-r--r--npc/008-2-16/_warps.txt3
-rw-r--r--npc/008-2-16/stove.txt87
-rw-r--r--npc/008-2-16/yannika.txt469
-rw-r--r--npc/008-2-17/_import.txt5
-rw-r--r--npc/008-2-17/_warps.txt5
-rw-r--r--npc/008-2-17/angus.txt19
-rw-r--r--npc/008-2-17/caul.txt19
-rw-r--r--npc/008-2-18/_import.txt4
-rw-r--r--npc/008-2-18/_warps.txt3
-rw-r--r--npc/008-2-18/malik.txt64
-rw-r--r--npc/008-2-19/_import.txt4
-rw-r--r--npc/008-2-19/_warps.txt3
-rw-r--r--npc/008-2-19/books.txt60
-rw-r--r--npc/008-2-2/_import.txt12
-rw-r--r--npc/008-2-2/_warps.txt6
-rw-r--r--npc/008-2-2/barron.txt32
-rw-r--r--npc/008-2-2/jukebox.txt29
-rw-r--r--npc/008-2-2/kfahr.txt785
-rw-r--r--npc/008-2-2/ledmitz.txt36
-rw-r--r--npc/008-2-2/mapflags.txt1
-rw-r--r--npc/008-2-2/melania.txt107
-rw-r--r--npc/008-2-2/melinda.txt181
-rw-r--r--npc/008-2-2/note.txt35
-rw-r--r--npc/008-2-2/shop.txt39
-rw-r--r--npc/008-2-20/_import.txt4
-rw-r--r--npc/008-2-20/_warps.txt4
-rw-r--r--npc/008-2-20/valia.txt19
-rw-r--r--npc/008-2-21/_import.txt4
-rw-r--r--npc/008-2-21/_mobs.txt3
-rw-r--r--npc/008-2-21/_warps.txt4
-rw-r--r--npc/008-2-22/_import.txt4
-rw-r--r--npc/008-2-22/_savepoints.txt15
-rw-r--r--npc/008-2-22/_warps.txt3
-rw-r--r--npc/008-2-23/_import.txt3
-rw-r--r--npc/008-2-23/_warps.txt3
-rw-r--r--npc/008-2-24/_import.txt5
-rw-r--r--npc/008-2-24/_warps.txt5
-rw-r--r--npc/008-2-24/chef.txt269
-rw-r--r--npc/008-2-24/troupe-leader.txt119
-rw-r--r--npc/008-2-25/_import.txt3
-rw-r--r--npc/008-2-25/_warps.txt4
-rw-r--r--npc/008-2-26/_import.txt3
-rw-r--r--npc/008-2-26/_warps.txt3
-rw-r--r--npc/008-2-27/_import.txt3
-rw-r--r--npc/008-2-27/_warps.txt3
-rw-r--r--npc/008-2-28/_import.txt3
-rw-r--r--npc/008-2-28/_warps.txt3
-rw-r--r--npc/008-2-29/_import.txt3
-rw-r--r--npc/008-2-29/_warps.txt3
-rw-r--r--npc/008-2-3/_import.txt5
-rw-r--r--npc/008-2-3/_savepoints.txt106
-rw-r--r--npc/008-2-3/_warps.txt3
-rw-r--r--npc/008-2-3/mapflags.txt1
-rw-r--r--npc/008-2-30/_import.txt3
-rw-r--r--npc/008-2-30/_warps.txt3
-rw-r--r--npc/008-2-31/_import.txt3
-rw-r--r--npc/008-2-31/_warps.txt3
-rw-r--r--npc/008-2-32/_import.txt4
-rw-r--r--npc/008-2-32/_warps.txt3
-rw-r--r--npc/008-2-32/thamas.txt83
-rw-r--r--npc/008-2-4/_import.txt7
-rw-r--r--npc/008-2-4/_savepoints.txt15
-rw-r--r--npc/008-2-4/_warps.txt3
-rw-r--r--npc/008-2-4/bernard.txt222
-rw-r--r--npc/008-2-4/mapflags.txt1
-rw-r--r--npc/008-2-4/olana.txt321
-rw-r--r--npc/008-2-5/_import.txt4
-rw-r--r--npc/008-2-5/_warps.txt3
-rw-r--r--npc/008-2-5/mapflags.txt1
-rw-r--r--npc/008-2-6/_import.txt6
-rw-r--r--npc/008-2-6/_warps.txt3
-rw-r--r--npc/008-2-6/alan.txt311
-rw-r--r--npc/008-2-6/donald.txt39
-rw-r--r--npc/008-2-6/mapflags.txt1
-rw-r--r--npc/008-2-7/_import.txt8
-rw-r--r--npc/008-2-7/_savepoints.txt15
-rw-r--r--npc/008-2-7/_warps.txt3
-rw-r--r--npc/008-2-7/mapflags.txt1
-rw-r--r--npc/008-2-7/shop.txt35
-rw-r--r--npc/008-2-7/simon.txt38
-rw-r--r--npc/008-2-7/wyara.txt29
-rw-r--r--npc/008-2-8/_import.txt6
-rw-r--r--npc/008-2-8/_warps.txt4
-rw-r--r--npc/008-2-8/macgowan.txt24
-rw-r--r--npc/008-2-8/mapflags.txt1
-rw-r--r--npc/008-2-8/nicholas.txt28
-rw-r--r--npc/008-2-9/_import.txt5
-rw-r--r--npc/008-2-9/_savepoints.txt15
-rw-r--r--npc/008-2-9/_warps.txt3
-rw-r--r--npc/008-2-9/mapflags.txt1
-rw-r--r--npc/008-3-0/_import.txt6
-rw-r--r--npc/008-3-0/_mobs.txt83
-rw-r--r--npc/008-3-0/_warps.txt3
-rw-r--r--npc/008-3-0/clauquer.txt138
-rw-r--r--npc/008-3-0/juliet.txt656
-rw-r--r--npc/008-3-1/_import.txt5
-rw-r--r--npc/008-3-1/_mobs.txt8
-rw-r--r--npc/008-3-1/_warps.txt3
-rw-r--r--npc/008-3-1/arkim.txt56
-rw-r--r--npc/008-3-2/_import.txt5
-rw-r--r--npc/008-3-2/_mobs.txt7
-rw-r--r--npc/008-3-2/_warps.txt3
-rw-r--r--npc/008-3-2/boss.txt43
-rw-r--r--npc/008-3-3/_import.txt4
-rw-r--r--npc/008-3-3/_mobs.txt9
-rw-r--r--npc/008-3-3/_warps.txt5
-rw-r--r--npc/008-3-4/_import.txt4
-rw-r--r--npc/008-3-4/_mobs.txt32
-rw-r--r--npc/008-3-4/_warps.txt5
-rw-r--r--npc/008-3-5/_import.txt7
-rw-r--r--npc/008-3-5/_mobs.txt12
-rw-r--r--npc/008-3-5/_warps.txt6
-rw-r--r--npc/008-3-5/bryant.txt79
-rw-r--r--npc/008-3-5/lordcave.txt101
-rw-r--r--npc/008-3-5/nunia.txt81
-rw-r--r--npc/008-3-6/_import.txt4
-rw-r--r--npc/008-3-6/_mobs.txt11
-rw-r--r--npc/008-3-6/_warps.txt3
-rw-r--r--npc/009-1/_import.txt10
-rw-r--r--npc/009-1/_mobs.txt33
-rw-r--r--npc/009-1/_warps.txt15
-rw-r--r--npc/009-1/blackwin.txt30
-rw-r--r--npc/009-1/forwin.txt24
-rw-r--r--npc/009-1/hamond.txt18
-rw-r--r--npc/009-1/soul-menhir.txt7
-rw-r--r--npc/009-1/thurstan.txt22
-rw-r--r--npc/009-1/wateranimation.txt10
-rw-r--r--npc/009-2-0/_import.txt3
-rw-r--r--npc/009-2-0/_warps.txt3
-rw-r--r--npc/009-2-1/_import.txt3
-rw-r--r--npc/009-2-1/_warps.txt3
-rw-r--r--npc/009-2-10/_import.txt3
-rw-r--r--npc/009-2-10/_warps.txt4
-rw-r--r--npc/009-2-11/_import.txt3
-rw-r--r--npc/009-2-11/_warps.txt3
-rw-r--r--npc/009-2-12/_import.txt3
-rw-r--r--npc/009-2-12/_warps.txt4
-rw-r--r--npc/009-2-13/_import.txt3
-rw-r--r--npc/009-2-13/_warps.txt4
-rw-r--r--npc/009-2-14/_import.txt3
-rw-r--r--npc/009-2-14/_warps.txt3
-rw-r--r--npc/009-2-15/_import.txt3
-rw-r--r--npc/009-2-15/_warps.txt5
-rw-r--r--npc/009-2-16/_import.txt3
-rw-r--r--npc/009-2-16/_warps.txt4
-rw-r--r--npc/009-2-17/_import.txt3
-rw-r--r--npc/009-2-17/_warps.txt4
-rw-r--r--npc/009-2-18/_import.txt3
-rw-r--r--npc/009-2-18/_warps.txt3
-rw-r--r--npc/009-2-2/_import.txt3
-rw-r--r--npc/009-2-2/_warps.txt3
-rw-r--r--npc/009-2-3/_import.txt6
-rw-r--r--npc/009-2-3/_warps.txt5
-rw-r--r--npc/009-2-3/barbara.txt17
-rw-r--r--npc/009-2-3/chef.txt91
-rw-r--r--npc/009-2-3/reid.txt22
-rw-r--r--npc/009-2-4/_import.txt5
-rw-r--r--npc/009-2-4/_warps.txt3
-rw-r--r--npc/009-2-4/aldred.txt17
-rw-r--r--npc/009-2-4/golbenez.txt51
-rw-r--r--npc/009-2-5/_import.txt5
-rw-r--r--npc/009-2-5/_warps.txt3
-rw-r--r--npc/009-2-5/lovers.txt29
-rw-r--r--npc/009-2-5/savaric.txt20
-rw-r--r--npc/009-2-6/_import.txt5
-rw-r--r--npc/009-2-6/_warps.txt3
-rw-r--r--npc/009-2-6/eurni.txt22
-rw-r--r--npc/009-2-6/jpmorbid.txt61
-rw-r--r--npc/009-2-7/_import.txt5
-rw-r--r--npc/009-2-7/_warps.txt3
-rw-r--r--npc/009-2-7/leofwin.txt18
-rw-r--r--npc/009-2-7/umfrey.txt25
-rw-r--r--npc/009-2-8/_import.txt4
-rw-r--r--npc/009-2-8/_warps.txt3
-rw-r--r--npc/009-2-8/cerhan.txt19
-rw-r--r--npc/009-2-9/_import.txt3
-rw-r--r--npc/009-2-9/_warps.txt4
-rw-r--r--npc/012-1/_import.txt18
-rw-r--r--npc/012-1/_mobs.txt12
-rw-r--r--npc/012-1/_warps.txt9
-rw-r--r--npc/012-1/aahna.txt17
-rw-r--r--npc/012-1/aidan.txt19
-rw-r--r--npc/012-1/ayasha.txt17
-rw-r--r--npc/012-1/crasmande.txt18
-rw-r--r--npc/012-1/hasan.txt18
-rw-r--r--npc/012-1/ishi.txt20
-rw-r--r--npc/012-1/kaan.txt19
-rw-r--r--npc/012-1/liana.txt25
-rw-r--r--npc/012-1/marine.txt17
-rw-r--r--npc/012-1/prawors.txt18
-rw-r--r--npc/012-1/tiki.txt150
-rw-r--r--npc/012-1/vincent.txt18
-rw-r--r--npc/012-1/wateranimation.txt12
-rw-r--r--npc/012-1/zegas.txt36
-rw-r--r--npc/012-2-1/_import.txt5
-rw-r--r--npc/012-2-1/_warps.txt4
-rw-r--r--npc/012-2-1/jessie.txt30
-rw-r--r--npc/012-2-1/tanisha.txt18
-rw-r--r--npc/012-2-2/_import.txt5
-rw-r--r--npc/012-2-2/_savepoints.txt28
-rw-r--r--npc/012-2-2/_warps.txt3
-rw-r--r--npc/012-2-2/sorfina.txt34
-rw-r--r--npc/012-2-3/_import.txt5
-rw-r--r--npc/012-2-3/_warps.txt3
-rw-r--r--npc/012-2-3/cynric.txt54
-rw-r--r--npc/012-2-3/nyle.txt67
-rw-r--r--npc/012-2-4/_import.txt5
-rw-r--r--npc/012-2-4/_warps.txt3
-rw-r--r--npc/012-2-4/morgan.txt22
-rw-r--r--npc/012-2-4/zitoni.txt76
-rw-r--r--npc/012-2-5/_import.txt5
-rw-r--r--npc/012-2-5/_warps.txt3
-rw-r--r--npc/012-2-5/rosen.txt20
-rw-r--r--npc/012-2-5/toichi.txt73
-rw-r--r--npc/012-2-6/_import.txt3
-rw-r--r--npc/012-2-6/_warps.txt3
-rw-r--r--npc/012-2-7/_import.txt5
-rw-r--r--npc/012-2-7/_savepoints.txt15
-rw-r--r--npc/012-2-7/_warps.txt3
-rw-r--r--npc/012-2-7/marazor.txt16
-rw-r--r--npc/012-3-1/_import.txt4
-rw-r--r--npc/012-3-1/_mobs.txt8
-rw-r--r--npc/012-3-1/_warps.txt5
-rw-r--r--npc/012-3-2/_import.txt4
-rw-r--r--npc/012-3-2/_mobs.txt8
-rw-r--r--npc/012-3-2/_warps.txt5
-rw-r--r--npc/012-3-3/_import.txt5
-rw-r--r--npc/012-3-3/_mobs.txt7
-rw-r--r--npc/012-3-3/_warps.txt3
-rw-r--r--npc/012-3-3/manatree.txt19
-rw-r--r--npc/020-1/_import.txt39
-rw-r--r--npc/020-1/_mobs.txt63
-rw-r--r--npc/020-1/_warps.txt46
-rw-r--r--npc/020-1/adrian.txt42
-rw-r--r--npc/020-1/aisha.txt18
-rw-r--r--npc/020-1/anwar.txt148
-rw-r--r--npc/020-1/bodyguard.txt53
-rw-r--r--npc/020-1/boss.txt43
-rw-r--r--npc/020-1/budifis.txt20
-rw-r--r--npc/020-1/cyndala.txt19
-rw-r--r--npc/020-1/ekinu.txt18
-rw-r--r--npc/020-1/eomie.txt192
-rw-r--r--npc/020-1/froma.txt19
-rw-r--r--npc/020-1/harper.txt18
-rw-r--r--npc/020-1/hocus.txt166
-rw-r--r--npc/020-1/inar.txt19
-rw-r--r--npc/020-1/issay.txt15
-rw-r--r--npc/020-1/itka.txt48
-rw-r--r--npc/020-1/joaquim.txt201
-rw-r--r--npc/020-1/joelin.txt18
-rw-r--r--npc/020-1/jossy.txt19
-rw-r--r--npc/020-1/mahoud.txt18
-rw-r--r--npc/020-1/malivox.txt23
-rw-r--r--npc/020-1/marikel.txt18
-rw-r--r--npc/020-1/marine.txt17
-rw-r--r--npc/020-1/martha.txt18
-rw-r--r--npc/020-1/neko.txt19
-rw-r--r--npc/020-1/nickos.txt18
-rw-r--r--npc/020-1/noke.txt19
-rw-r--r--npc/020-1/odonell.txt18
-rw-r--r--npc/020-1/philip.txt18
-rw-r--r--npc/020-1/popaul.txt19
-rw-r--r--npc/020-1/pusco.txt20
-rw-r--r--npc/020-1/ryan.txt18
-rw-r--r--npc/020-1/sander.txt18
-rw-r--r--npc/020-1/tindris.txt30
-rw-r--r--npc/020-1/vaspina.txt20
-rw-r--r--npc/020-1/wateranimation.txt20
-rw-r--r--npc/020-2-0/_import.txt5
-rw-r--r--npc/020-2-0/_mobs.txt5
-rw-r--r--npc/020-2-0/_warps.txt3
-rw-r--r--npc/020-2-0/kaizer.txt18
-rw-r--r--npc/020-2-1/_import.txt3
-rw-r--r--npc/020-2-1/_warps.txt5
-rw-r--r--npc/020-2-10/_import.txt4
-rw-r--r--npc/020-2-10/_warps.txt4
-rw-r--r--npc/020-2-10/hetchel.txt33
-rw-r--r--npc/020-2-11/_import.txt3
-rw-r--r--npc/020-2-11/_warps.txt3
-rw-r--r--npc/020-2-12/_import.txt3
-rw-r--r--npc/020-2-12/_warps.txt3
-rw-r--r--npc/020-2-13/_import.txt3
-rw-r--r--npc/020-2-13/_warps.txt3
-rw-r--r--npc/020-2-14/_import.txt3
-rw-r--r--npc/020-2-14/_warps.txt3
-rw-r--r--npc/020-2-15/_import.txt7
-rw-r--r--npc/020-2-15/_warps.txt3
-rw-r--r--npc/020-2-15/eleanore.txt16
-rw-r--r--npc/020-2-15/kadiya.txt21
-rw-r--r--npc/020-2-15/memoriam.txt19
-rw-r--r--npc/020-2-15/yumi.txt54
-rw-r--r--npc/020-2-16/_import.txt3
-rw-r--r--npc/020-2-16/_warps.txt3
-rw-r--r--npc/020-2-17/_import.txt3
-rw-r--r--npc/020-2-17/_warps.txt3
-rw-r--r--npc/020-2-18/_import.txt4
-rw-r--r--npc/020-2-18/_warps.txt4
-rw-r--r--npc/020-2-18/inya.txt19
-rw-r--r--npc/020-2-19/_import.txt3
-rw-r--r--npc/020-2-19/_warps.txt3
-rw-r--r--npc/020-2-2/_import.txt3
-rw-r--r--npc/020-2-2/_warps.txt4
-rw-r--r--npc/020-2-20/_import.txt5
-rw-r--r--npc/020-2-20/_warps.txt6
-rw-r--r--npc/020-2-20/drabur.txt54
-rw-r--r--npc/020-2-20/riskim.txt152
-rw-r--r--npc/020-2-21/_import.txt3
-rw-r--r--npc/020-2-21/_warps.txt3
-rw-r--r--npc/020-2-22/_import.txt3
-rw-r--r--npc/020-2-22/_warps.txt5
-rw-r--r--npc/020-2-23/_import.txt3
-rw-r--r--npc/020-2-23/_warps.txt4
-rw-r--r--npc/020-2-24/_import.txt4
-rw-r--r--npc/020-2-24/_warps.txt4
-rw-r--r--npc/020-2-24/kylian.txt130
-rw-r--r--npc/020-2-25/_import.txt3
-rw-r--r--npc/020-2-25/_warps.txt6
-rw-r--r--npc/020-2-26/_import.txt4
-rw-r--r--npc/020-2-26/_warps.txt9
-rw-r--r--npc/020-2-26/receptionist.txt21
-rw-r--r--npc/020-2-27/_import.txt3
-rw-r--r--npc/020-2-27/_warps.txt4
-rw-r--r--npc/020-2-28/_import.txt4
-rw-r--r--npc/020-2-28/_warps.txt5
-rw-r--r--npc/020-2-28/pauline.txt39
-rw-r--r--npc/020-2-29/_import.txt3
-rw-r--r--npc/020-2-29/_warps.txt4
-rw-r--r--npc/020-2-3/_import.txt4
-rw-r--r--npc/020-2-3/_warps.txt4
-rw-r--r--npc/020-2-3/inac.txt18
-rw-r--r--npc/020-2-30/_import.txt4
-rw-r--r--npc/020-2-30/_warps.txt3
-rw-r--r--npc/020-2-30/david.txt42
-rw-r--r--npc/020-2-31/_import.txt3
-rw-r--r--npc/020-2-31/_warps.txt4
-rw-r--r--npc/020-2-32/_import.txt3
-rw-r--r--npc/020-2-32/_warps.txt4
-rw-r--r--npc/020-2-33/_import.txt3
-rw-r--r--npc/020-2-33/_warps.txt4
-rw-r--r--npc/020-2-34/_import.txt5
-rw-r--r--npc/020-2-34/_warps.txt3
-rw-r--r--npc/020-2-34/casino.txt17
-rw-r--r--npc/020-2-34/donutello.txt166
-rw-r--r--npc/020-2-4/_import.txt3
-rw-r--r--npc/020-2-4/_warps.txt3
-rw-r--r--npc/020-2-5/_import.txt5
-rw-r--r--npc/020-2-5/_warps.txt5
-rw-r--r--npc/020-2-5/dausen.txt19
-rw-r--r--npc/020-2-5/filipa.txt19
-rw-r--r--npc/020-2-6/_import.txt3
-rw-r--r--npc/020-2-6/_warps.txt5
-rw-r--r--npc/020-2-7/_import.txt4
-rw-r--r--npc/020-2-7/_warps.txt3
-rw-r--r--npc/020-2-7/manoli.txt19
-rw-r--r--npc/020-2-8/_import.txt5
-rw-r--r--npc/020-2-8/_warps.txt3
-rw-r--r--npc/020-2-8/heathin.txt19
-rw-r--r--npc/020-2-8/jhedia.txt19
-rw-r--r--npc/020-2-9/_import.txt5
-rw-r--r--npc/020-2-9/_warps.txt3
-rw-r--r--npc/020-2-9/hydusun.txt62
-rw-r--r--npc/020-2-9/yanis.txt18
-rw-r--r--npc/_anchors.txt53
-rw-r--r--npc/_import.txt176
-rw-r--r--npc/botcheck/_import.txt2
-rw-r--r--npc/commands/bodytype.txt53
-rw-r--r--npc/commands/debug-look.txt83
-rw-r--r--npc/commands/debug-preset.txt253
-rw-r--r--npc/commands/debug-quest.txt217
-rw-r--r--npc/commands/debug-skill.txt94
-rw-r--r--npc/commands/debug.txt145
-rw-r--r--npc/commands/event.txt57
-rw-r--r--npc/commands/gm.txt41
-rw-r--r--npc/commands/mobinfo.txt29
-rw-r--r--npc/commands/motd.txt194
-rw-r--r--npc/commands/music.txt75
-rw-r--r--npc/commands/python.txt24
-rw-r--r--npc/commands/rate-management.txt107
-rw-r--r--npc/commands/resync.txt40
-rw-r--r--npc/commands/scheduled-broadcasts.txt227
-rw-r--r--npc/commands/super-menu.txt68
-rw-r--r--npc/commands/warp.txt91
-rw-r--r--npc/commands/zeny.txt98
-rw-r--r--npc/config/hairstyle_config.txt26
-rw-r--r--npc/config/location.txt83
-rw-r--r--npc/config/magic.txt451
-rw-r--r--npc/dev/ci_test.txt47
-rw-r--r--npc/dev/test.txt814
-rw-r--r--npc/fermi/_import.txt3
-rw-r--r--npc/fermi/_warps.txt3
-rw-r--r--npc/functions/RNGesus.txt87
-rw-r--r--npc/functions/afk.txt69
-rw-r--r--npc/functions/array.txt445
-rw-r--r--npc/functions/asklanguage.txt56
-rw-r--r--npc/functions/asleep.txt19
-rw-r--r--npc/functions/bank.txt297
-rw-r--r--npc/functions/barber.txt220
-rw-r--r--npc/functions/beds.txt22
-rw-r--r--npc/functions/bitwise.txt66
-rw-r--r--npc/functions/bodytype.txt19
-rw-r--r--npc/functions/casino.txt254
-rw-r--r--npc/functions/clientversion.txt20
-rw-r--r--npc/functions/confused-tree-dict.txt515
-rw-r--r--npc/functions/crafting.txt119
-rw-r--r--npc/functions/daily.txt154
-rw-r--r--npc/functions/doors.txt65
-rw-r--r--npc/functions/event-listeners.txt169
-rw-r--r--npc/functions/faction.txt104
-rw-r--r--npc/functions/fishing.txt401
-rw-r--r--npc/functions/game-rules.txt66
-rw-r--r--npc/functions/generic-text.txt120
-rw-r--r--npc/functions/global_event_handler.txt73
-rw-r--r--npc/functions/goodbye.txt28
-rw-r--r--npc/functions/hammocks.txt50
-rw-r--r--npc/functions/harbours.txt39
-rw-r--r--npc/functions/hello.txt23
-rw-r--r--npc/functions/input.txt66
-rw-r--r--npc/functions/inventoryplace.txt37
-rw-r--r--npc/functions/legacy.txt238
-rw-r--r--npc/functions/legiontalk.txt66
-rw-r--r--npc/functions/libquest.txt104
-rw-r--r--npc/functions/lockpicks.txt193
-rw-r--r--npc/functions/main.txt445
-rw-r--r--npc/functions/manhole.txt73
-rw-r--r--npc/functions/masks.txt43
-rw-r--r--npc/functions/math.txt50
-rw-r--r--npc/functions/mouboofunc.txt89
-rw-r--r--npc/functions/music.txt87
-rw-r--r--npc/functions/npcmove.txt142
-rw-r--r--npc/functions/npcmovegraph.txt485
-rw-r--r--npc/functions/openbook.txt34
-rw-r--r--npc/functions/permissions.txt35
-rw-r--r--npc/functions/player-cache.txt501
-rw-r--r--npc/functions/quest-debug/000-ShipQuests_Julia.txt37
-rw-r--r--npc/functions/quest-debug/001-ShipQuests_Arpan.txt27
-rw-r--r--npc/functions/quest-debug/002-ShipQuests_Alige.txt27
-rw-r--r--npc/functions/quest-debug/003-ShipQuests_Peter.txt36
-rw-r--r--npc/functions/quest-debug/004-ShipQuests_Nard.txt38
-rw-r--r--npc/functions/quest-debug/005-ShipQuests_Knife.txt25
-rw-r--r--npc/functions/quest-debug/006-ShipQuests_ArpanMoney.txt27
-rw-r--r--npc/functions/quest-debug/007-ShipQuests_Door.txt25
-rw-r--r--npc/functions/quest-debug/008-ShipQuests_Couwan.txt26
-rw-r--r--npc/functions/quest-debug/009-ShipQuests_TreasureChest.txt25
-rw-r--r--npc/functions/quest-debug/010-ShipQuests_Ale.txt25
-rw-r--r--npc/functions/quest-debug/011-ShipQuests_Astapolos.txt25
-rw-r--r--npc/functions/quest-debug/012-ShipQuests_Gulukan.txt25
-rw-r--r--npc/functions/quest-debug/013-ShipQuests_Jalad.txt25
-rw-r--r--npc/functions/quest-debug/014-ShipQuests_QMuller.txt25
-rw-r--r--npc/functions/quest-debug/015-ShipQuests_Tibbo.txt25
-rw-r--r--npc/functions/quest-debug/016-ShipQuests_Gugli.txt48
-rw-r--r--npc/functions/quest-debug/017-ShipQuests_ChefGado.txt30
-rw-r--r--npc/functions/quest-debug/018-General_Cookies.txt25
-rw-r--r--npc/functions/quest-debug/020-ArtisQuests_LazyBrother.txt28
-rw-r--r--npc/functions/quest-debug/021-ArtisQuests_Urchin.txt26
-rw-r--r--npc/functions/quest-debug/022-ArtisQuests_CatchPiou.txt26
-rw-r--r--npc/functions/quest-debug/023-ArtisQuests_Fishman.txt26
-rw-r--r--npc/functions/quest-debug/024-ArtisQuests_QOnan.txt27
-rw-r--r--npc/functions/quest-debug/026-General_Rumly.txt27
-rw-r--r--npc/functions/quest-debug/027-ArtisQuests_Enora.txt49
-rw-r--r--npc/functions/quest-debug/029-ArtisQuests_Fexil.txt27
-rw-r--r--npc/functions/quest-debug/030-ArtisQuests_Lloyd.txt25
-rw-r--r--npc/functions/quest-debug/031-General_Janus.txt31
-rw-r--r--npc/functions/quest-debug/032-ArtisQuests_MonaDad.txt26
-rw-r--r--npc/functions/quest-debug/033-Artis_Legion_Progress.txt31
-rw-r--r--npc/functions/quest-debug/034-ArtisQuests_TrainingLegion.txt28
-rw-r--r--npc/functions/quest-debug/035-ThiefQuests_Artis.txt38
-rw-r--r--npc/functions/quest-debug/050-HurnscaldQuests_Hinnak.txt32
-rw-r--r--npc/functions/quest-debug/051-HurnscaldQuests_Soup.txt32
-rw-r--r--npc/functions/quest-debug/052-HurnscaldQuests_Inspector.txt41
-rw-r--r--npc/functions/quest-debug/053-HurnscaldQuests_ForestBow.txt42
-rw-r--r--npc/functions/quest-debug/054-HurnscaldQuests_WoodenShield.txt37
-rw-r--r--npc/functions/quest-debug/055-General_Cooking.txt92
-rw-r--r--npc/functions/quest-debug/056-General_Brotherhood.txt27
-rw-r--r--npc/functions/quest-debug/057-HurnscaldQuests_Kfahr.txt31
-rw-r--r--npc/functions/quest-debug/058-ArgaesQuest_Galimatia.txt32
-rw-r--r--npc/functions/quest-debug/059-HurnscaldQuests_Rossy.txt43
-rw-r--r--npc/functions/quest-debug/061-General_Hal.txt30
-rw-r--r--npc/functions/quest-debug/100-General_Narrator.txt27
-rw-r--r--npc/functions/quest-debug/functions.txt109
-rw-r--r--npc/functions/questgen.txt38
-rw-r--r--npc/functions/referral.txt43
-rw-r--r--npc/functions/refine.txt66
-rw-r--r--npc/functions/resetstatus.txt117
-rw-r--r--npc/functions/riddle.txt74
-rw-r--r--npc/functions/sailordialogue.txt53
-rw-r--r--npc/functions/sailortalk.txt37
-rw-r--r--npc/functions/savepoint.txt57
-rw-r--r--npc/functions/scoreboards.txt291
-rw-r--r--npc/functions/shops.txt18
-rw-r--r--npc/functions/skills.txt20
-rw-r--r--npc/functions/soul-menhir.txt75
-rw-r--r--npc/functions/spotlight.txt92
-rw-r--r--npc/functions/string.txt196
-rw-r--r--npc/functions/time.txt108
-rw-r--r--npc/functions/timer.txt63
-rw-r--r--npc/functions/treasure.txt134
-rw-r--r--npc/functions/util.txt102
-rw-r--r--npc/functions/vault.txt98
-rw-r--r--npc/functions/villagertalk.txt53
-rw-r--r--npc/functions/warp.txt58
-rw-r--r--npc/items/cookie.txt22
-rw-r--r--npc/items/croconut.txt72
-rw-r--r--npc/items/gift.txt35
-rw-r--r--npc/items/master_skillbook.txt164
-rw-r--r--npc/items/music_toys.txt18
-rw-r--r--npc/items/rand_sc_heal.txt85
-rw-r--r--npc/items/recipes.txt352
-rw-r--r--npc/items/shovel.txt361
-rw-r--r--npc/marine-2/_import.txt4
-rw-r--r--npc/marine-2/_mobs.txt4
-rw-r--r--npc/marine-2/main.txt60
-rw-r--r--npc/marine/_import.txt4
-rw-r--r--npc/marine/_mobs.txt3
-rw-r--r--npc/marine/saluc.txt137
-rw-r--r--npc/pre-re/scripts_main.conf4
-rw-r--r--npc/scripts.conf178
-rw-r--r--npc/sec_pri/_import.txt3
-rw-r--r--npc/sec_pri/redirect.txt12
-rw-r--r--npc/test/_import.txt12
-rw-r--r--npc/test/_mobs.txt15
-rw-r--r--npc/test/mapflags.txt2
-rw-r--r--npc/test/npc1.txt712
-rw-r--r--npc/test/npc2.txt35
-rw-r--r--npc/test/npc3.txt7
-rw-r--r--npc/test/npc4.txt30
-rw-r--r--npc/test/npc5.txt34
-rw-r--r--npc/test/npc6.txt23
-rw-r--r--npc/test/test1.txt165
-rw-r--r--npc/test/test2.txt13
-rw-r--r--npc/testbg/_import.txt3
-rw-r--r--npc/testbg/mapflags.txt1
939 files changed, 49208 insertions, 0 deletions
diff --git a/npc/000-0-0/_import.txt b/npc/000-0-0/_import.txt
new file mode 100644
index 00000000..039280fe
--- /dev/null
+++ b/npc/000-0-0/_import.txt
@@ -0,0 +1,5 @@
+// Map 000-0-0: Sailor's Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-0-0/mapflags.txt",
+"npc/000-0-0/q'onan.txt",
+"npc/000-0-0/sailors.txt",
diff --git a/npc/000-0-0/mapflags.txt b/npc/000-0-0/mapflags.txt
new file mode 100644
index 00000000..0ed6ce16
--- /dev/null
+++ b/npc/000-0-0/mapflags.txt
@@ -0,0 +1 @@
+000-0-0 mapflag invisible
diff --git a/npc/000-0-0/q'onan.txt b/npc/000-0-0/q'onan.txt
new file mode 100644
index 00000000..a0fc844a
--- /dev/null
+++ b/npc/000-0-0/q'onan.txt
@@ -0,0 +1,14 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Vasily_Makarov
+// Description:
+// Sleeping and snoring NPC.
+
+000-0-0,29,28,0 script Q'Onan#000-0-0 NPC_ORC_SAILOR,{
+ asleep;
+ close;
+
+OnInit:
+ end;
+}
diff --git a/npc/000-0-0/sailors.txt b/npc/000-0-0/sailors.txt
new file mode 100644
index 00000000..d72d55f2
--- /dev/null
+++ b/npc/000-0-0/sailors.txt
@@ -0,0 +1,92 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Qwerty Dragon
+// Description:
+// Introduction scene where two sailors talk about how the player was found on his raft.
+// Elmo will handle dialogs between both NPCs.
+
+000-0-0,26,23,0 script Elmo#sailors NPC_ELMO,{
+
+OnTalk:
+ deltimer("Elmo#sailors::OnSlow");
+ setcamnpc;
+ mesn "Elmo";
+ mesq l("Poor thing. Fortunately we were more attentive than the sharks in these waters. I wonder where this tragic journey started. By the way, did you see the logo on that raft?");
+ next;
+
+ mesn "Magic Arpan";
+ mesq l("Yeye, it's the logo of the Legion of Aemil in Esperia! I wonder what this yoiis was doing so far away from the coast.");
+ next;
+
+ mesn "Elmo";
+ mesq l("I wonder too...");
+ next;
+
+ mesn "Magic Arpan";
+ mesq l("Did you hear about all those missing people last month? Maybe this is the yoiis from Esperia who got a secret diplomatic mission from the Legion of Aemil!");
+ next;
+
+ mesn "Elmo";
+ mesq l("Makes sense. Do you think we should inform the capt'n about it?");
+ next;
+
+ mesn "Magic Arpan";
+ mesq l("Yeye.");
+ next;
+
+ mesn "Elmo";
+ mesq l("Alright, I'm going to his room. Keep watch, not that our new friend turns out to be a foe after all...");
+ next;
+
+ mesn "Magic Arpan";
+ mesq l("I will yaying do.");
+ next;
+
+ mesn "Elmo";
+ mesq l("Oh, and give our friend - or foe - some clothes, that shabby rags are in even worse condition than ours.");
+ next;
+
+ mesn "Magic Arpan";
+ mesq l("Yayayaya, it's the first time someone is dressed worse than us!");
+ next;
+
+ mesn "Elmo";
+ mesq l("Hehe... Ok, I'm going to inform the capt'n up there.");
+ next;
+
+ mesn "Magic Arpan";
+ mesq l("I'll bring everything that is needed, don't worry.");
+ next;
+
+ mesn "Elmo";
+ mesq l("Oh, look who is waking up!");
+ next;
+
+ restorecam;
+ adddefaultskills;
+ setq General_Narrator, 0;
+ addtimer(45000,"Magic Arpan::OnSlow");
+ warp "000-2-1", 50, 38;
+ savepoint "000-2-1", 50, 38;
+ percentheal 100, 100;
+ closeclientdialog;
+ close;
+
+OnInit:
+ end;
+
+OnSlow:
+ npctalk3(l("(Click on us to continue the introduction.)"));
+ dispbottom(l("Click on the NPCs (Non-Player Characters) around you to continue the introduction."));
+ addtimer(60000,"Elmo#sailors::OnSlow");
+ close;
+}
+
+000-0-0,25,23,0 script Magic Arpan#sailors NPC_MAGIC_ARPAN,{
+ doevent "Elmo#sailors::OnTalk";
+ close;
+
+OnInit:
+ end;
+}
diff --git a/npc/000-0-1/_import.txt b/npc/000-0-1/_import.txt
new file mode 100644
index 00000000..ed783937
--- /dev/null
+++ b/npc/000-0-1/_import.txt
@@ -0,0 +1,4 @@
+// Map 000-0-1: Sailor's Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-0-1/mapflags.txt",
+"npc/000-0-1/narrator.txt",
diff --git a/npc/000-0-1/mapflags.txt b/npc/000-0-1/mapflags.txt
new file mode 100644
index 00000000..04d1aea5
--- /dev/null
+++ b/npc/000-0-1/mapflags.txt
@@ -0,0 +1 @@
+000-0-1 mapflag invisible
diff --git a/npc/000-0-1/narrator.txt b/npc/000-0-1/narrator.txt
new file mode 100644
index 00000000..d1bf14e8
--- /dev/null
+++ b/npc/000-0-1/narrator.txt
@@ -0,0 +1,180 @@
+// Evol scripts.
+// Moubootaur Legends scripts.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// Narrator explain to the player that he is dreaming.
+// Variable:
+// Q General_Narrator
+// Values:
+// 0 PC is in the game introduction.
+// 1 PC arrived Artis.
+// 2 PC arrived in Argaes.
+
+000-0-1,25,28,0 script Narrator#000-0-1 NPC_NARRATOR,{
+ function referralSystem;
+ function travelToArtis;
+ function travelToArgaes;
+
+ switch (getq(General_Narrator)) {
+ case 0:
+ travelToArtis();
+ break;
+ case 1:
+ travelToArgaes();
+ break;
+ default:
+ mesc(l("ERROR - Corrupted quest state %d", getq(General_Narrator)), 1);
+ mesc(l("Please contact the staff for technical support."), 1);
+ mes("");
+ mesc(l("Error message: Narrator#000-0-1 Invalid Quest State"));
+ break;
+ }
+ closeclientdialog();
+ close;
+
+OnInit:
+
+ if (debug > 0) {
+ // debug commands to skip the tutorial
+ bindatcmd("force-referral", sprintf("%s::referralSystem", .name$));
+ bindatcmd("force-artis", sprintf("%s::travelToArtis", .name$));
+ }
+ end;
+
+ ///////////////////////////////////////////////////////////////////////
+ // Quest state: 0
+ public function travelToArtis {
+ narrator(S_LAST_NEXT,
+ l("Look, we finally meet."),
+ l("I think that you already understood, you are asleep."),
+ l("The ship, La Johanne, has left Drasil Island, finally."),
+ l("Nard and his crew are taking us to the city of Artis."));
+
+ // Legacy accounts are excluded
+ // Only one referral per vault account
+ .@refVault = bitwise_get(getvaultvar(REFERRAL_PROG), 0x00FFFFFF, 0);
+
+ if (!islegacyaccount() && .@refVault < 1) {
+ referralSystem();
+ }
+
+ narrator(S_LAST_CLOSE,
+ l("There are a lot of things you must be wondering about."),
+ l("So, search for answers."),
+ l("..."),
+ l("Ah, seagulls. We are arriving."),
+ l("..."),
+ l("Wake-up!"));
+
+ if (.@cnt = countitem(JohanneKey)) {
+ delitem(JohanneKey, .@cnt);
+ }
+
+ setq(General_Narrator, 1);
+ setq(ShipQuests_Nard, 6);
+ savepoint("001-2-22", 50, 38);
+ warp("SavePoint", 0, 0);
+ return;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Quest state: 1
+ function travelToArgaes {
+ narrator(S_LAST_NEXT,
+ l("Oh, hello again!"),
+ l("I hope you still remember me."),
+ l("Now, this ship is not the most comfortable, don't you agree?"),
+ l("Well, hopefully it won't be too long until you reach your destination."),
+ l("Argaes, in the ancient continent of Ancea..."),
+ l("What could be waiting for you there?"));
+
+ // Special dialog for Legacy accounts
+ // To relate to Doomsday event
+ if (islegacyaccount()) {
+ narrator(S_LAST_NEXT,
+ l("Maybe you already have been on that continent before."),
+ l("Also, don't you think this ship vaguely... familiar?"),
+ l("Well, not like you would be able to remember. Even if you wanted."),
+ l("Ah, sorry. I make too many rhetorical questions, don't I?"),
+ l("I probably should let you rest, it must have been tiring!"),
+ l("But before that, one last question..."));
+ }
+
+ narrator(S_LAST_CLOSE,
+ l("Actually... Wouldn't now be a good time to wake up?"));
+
+ setq(General_Narrator, 2);
+ savepoint("008-1-1", 33, 63);
+ warp("SavePoint", 0, 0);
+ dispbottom(l("After a tiring, yet fast travel by ship, you arrive at %s.", l("Woodlands")));
+ close;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Script Utils
+ // referralSystem() is a Moubootaur Legends function
+ public function referralSystem {
+ mesc(l("But before we get there, I've been itching to know..."));
+ next();
+ mesc(l("Do we know someone on this world?"), 1); // FIXME: awkward wording: suddenly changes from singular first person (I) to plural second person (we)
+
+ // Opt-out
+ if (askyesno() == ASK_NO) {
+ mesc(l("Yes. We truly don't remember anyone.")); // FIXME: juxtaposition of Yes and No (probably should be "No, we truly don't...")
+ next();
+ return;
+ }
+
+ // Opt-in
+ mesc(l("Yes... We remember a fellow adventurer... What was their name again?"));
+ next();
+
+ do {
+ mesc(l("(Which player invited you to this world?)"), 1); // FIXME: suddenly changes to the third person (invited "you" vs invited "us" or invited "me")
+ input(.@refName$ = "");
+ mes("");
+
+ .@refName$ = strip(.@refName$); // clean it up
+
+ if (.@refName$ == "") {
+ mesc(l("Actually, nevermind. My memory is still too foggy to remember this.")); // FIXME: suddenly changes from plural second person to singular first person ("My" memory)
+ next();
+ break;
+ }
+
+ .@refVault = "playerCache"::name2vault(.@refName$);
+
+ if (.@refVault == 0) {
+ mesc(l("Oops, there is nobody known as %s on this word.", .@refName$)); // FIXME: this is too informal
+ mesc(l("Maybe I don't remember their name, after all."));
+ next();
+ sleep2(400); // Anti-spam Forced cooldowns
+ // FIXME: show a message to the player (use a variable to throttle instead of sleep2)
+ continue;
+ }
+
+
+ if (.@refVault == getvaultid()) {
+ mesc(l("Hahah, silly, that's ourselves!"));
+ mesc(l("Try again!"));
+ next();
+ sleep2(200); // Anti-spam Forced cooldowns
+ // FIXME: show a message to the player (use a variable to throttle instead of sleep2)
+ continue;
+ }
+
+ bitwise_set(getvaultvar(REFERRAL_PROG), 0x00FFFFFF, 0, .@refVault);
+ //getitembound(FriendGift, 1, 1);
+ mesc(l("Ah yes, our trusty friend, %s.", .@refName$));
+ mesc(l("They probably miss me. I mean, I probably have been away for a long time..."));
+ next();
+ mesc(l("Maybe they sent me a letter, or a gift? I'll see once I get in Artis."));
+ next();
+ break;
+ } while (true);
+
+ return;
+ }
+}
diff --git a/npc/000-0/_import.txt b/npc/000-0/_import.txt
new file mode 100644
index 00000000..75f2626b
--- /dev/null
+++ b/npc/000-0/_import.txt
@@ -0,0 +1,4 @@
+// Map 000-0: Oceania
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-0/mapflags.txt",
+"npc/000-0/sailors.txt",
diff --git a/npc/000-0/mapflags.txt b/npc/000-0/mapflags.txt
new file mode 100644
index 00000000..e956447e
--- /dev/null
+++ b/npc/000-0/mapflags.txt
@@ -0,0 +1 @@
+000-0 mapflag invisible
diff --git a/npc/000-0/sailors.txt b/npc/000-0/sailors.txt
new file mode 100644
index 00000000..d19d4f39
--- /dev/null
+++ b/npc/000-0/sailors.txt
@@ -0,0 +1,92 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Qwerty Dragon
+// Reid
+// Vasily_Makarov
+// Jesusalva
+// Description:
+// Starting script of Evol Online.
+
+000-0,23,20,0 script Sailors NPC_SAILORS,6,6,{
+
+OnTouch:
+ checkclientversion;
+ .@lang = requestlang();
+ if (.@lang >= 0 && .@lang <= MAX_LANG) Lang = .@lang;
+
+ mesn l("Narrator");
+ mesc(l("You are on a raft, adrift in the sea."), 9);
+ next;
+ mesc(l("With hunger, thirst, and sleep as your only companions, you have the disturbing realization that you can't remember anything of your former life or identity."), 9);
+ next;
+ mesc(l("All of a sudden, you hear voices from above."), 9);
+ next;
+ mesc(l("Your body aches, even your hair hurts, and the bright daylight is painful."), 9);
+ next;
+ mesc(l("But still, you open your eyes and see a large ship before you!"), 9);
+ next;
+ mesc(l("Aboard stand sailors trying to communicate with you."), 9);
+ next;
+
+ setcamnpc "Sailors", -64, -32;
+ mesn l("Kralog Voice");
+ mesq l("Hey Frenchy!");
+ next;
+
+ setcamnpc "Sailors", 0, -32;
+ mesn l("Human Voice");
+ mesq l("Nah, clearly from the East...");
+ next;
+
+ setcamnpc "Sailors", 144, -80;
+ mesn l("Tritan Voice");
+ mesq l("What are you guys saying ? It's a Yoiis!");
+ next;
+
+ setcamnpc;
+ mesn l("Raijin Voice");
+ mesq l("From the East? As in... Ancea?");
+ next;
+ mesq l("Hey you! Can you hear us? Are you okay?");
+ next;
+ restorecam;
+
+ asklanguage(LANG_ON_SEA);
+
+ // Players coming from TMW Legacy didn't got a chance to do this yet.
+ // So allow them now.
+ if (islegacyaccount()) {
+ // Rebirth system
+ if (getlegacylevel() > 90)
+ REBIRTH=1;
+
+ // Race selection
+ BarberChangeRace();
+ }
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Oh, still alive? What a relive!");
+ next;
+ setcamnpc "Sailors", 144, -80;
+ mesq l("This castaway needs help, on to the rescue!");
+ next;
+ restorecam;
+
+ mesn l("Narrator");
+ mesc(l("The sailors take you aboard their ship."), 9);
+ next;
+ mesc(l("Click on the NPCs (Non-Player Characters) around you to continue the introduction."), 9);
+ next;
+
+ addtimer(15000,"Elmo#sailors::OnSlow");
+ warp "000-0-0", 26, 28;
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ end;
+}
diff --git a/npc/000-1/_import.txt b/npc/000-1/_import.txt
new file mode 100644
index 00000000..55b14a90
--- /dev/null
+++ b/npc/000-1/_import.txt
@@ -0,0 +1,24 @@
+// Map 000-1: Drasil Island
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-1/_mobs.txt",
+"npc/000-1/_warps.txt",
+"npc/000-1/ale.txt",
+"npc/000-1/astapolos.txt",
+"npc/000-1/boss.txt",
+"npc/000-1/chest.txt",
+"npc/000-1/couwan.txt",
+"npc/000-1/darlin.txt",
+"npc/000-1/fexil.txt",
+"npc/000-1/gugli.txt",
+"npc/000-1/gulukan.txt",
+"npc/000-1/jalad.txt",
+"npc/000-1/lean.txt",
+"npc/000-1/mapflags.txt",
+"npc/000-1/maxe.txt",
+"npc/000-1/muller.txt",
+"npc/000-1/panels.txt",
+"npc/000-1/sapartan.txt",
+"npc/000-1/shop.txt",
+"npc/000-1/silvio.txt",
+"npc/000-1/tarlan.txt",
+"npc/000-1/tibbo.txt",
diff --git a/npc/000-1/_mobs.txt b/npc/000-1/_mobs.txt
new file mode 100644
index 00000000..4a1f05b5
--- /dev/null
+++ b/npc/000-1/_mobs.txt
@@ -0,0 +1,38 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-1: Drasil Island mobs
+000-1,28,49,6,9 monster Tortuga 1004,3,16000,120000
+000-1,58,118,34,14 monster Tortuga 1004,4,35000,300000
+000-1,71,95,4,12 monster Tortuga 1004,1,35000,300000
+000-1,52,92,4,17 monster Tortuga 1004,2,35000,300000
+000-1,37,66,11,5 monster Tortuga 1004,2,35000,120000
+000-1,42,41,9,16 monster Tortuga 1004,2,35000,120000
+000-1,87,37,12,11 monster Tortuga 1004,3,35000,120000
+000-1,44,75,2,1 monster Little Blub 1007,2,25000,120000
+000-1,61,64,7,10 monster Little Blub 1007,2,25000,120000
+000-1,62,25,10,4 monster Little Blub 1007,2,25000,120000
+000-1,85,33,2,3 monster Little Blub 1007,1,25000,120000
+000-1,85,58,14,9 monster Little Blub 1007,2,35000,120000
+000-1,48,61,9,6 monster Little Blub 1007,1,35000,120000
+000-1,28,48,3,5 monster Little Blub 1007,1,35000,120000
+000-1,35,50,0,1 monster Plushroom Field 1011,1,35000,150000
+000-1,54,115,0,1 monster Plushroom Field 1011,1,35000,150000
+000-1,63,80,4,2 monster Plushroom Field 1011,1,35000,150000
+000-1,54,64,0,2 monster Plushroom Field 1011,1,35000,150000
+000-1,78,58,4,5 monster Plushroom Field 1011,2,35000,150000
+000-1,71,62,1,1 monster Plushroom Field 1011,1,35000,150000
+000-1,32,116,8,9 monster Croc 1006,2,35000,300000
+000-1,63,31,10,3 monster Croc 1006,1,35000,300000
+000-1,76,68,1,1 monster Croc 1006,1,35000,300000
+000-1,52,92,4,17 monster Croc 1006,1,35000,300000
+000-1,71,77,4,4 monster Croc 1006,1,35000,300000
+000-1,0,0,0,0 monster Piou 1002,4,60000,15000
+000-1,78,115,0,0 monster Crocotree 1010,1,420000,240000
+000-1,57,104,0,0 monster Crocotree 1010,1,420000,240000
+000-1,39,112,0,0 monster Crocotree 1010,1,420000,240000
+000-1,67,93,0,0 monster Crocotree 1010,1,420000,240000
+000-1,53,77,0,0 monster Crocotree 1010,1,420000,240000
+000-1,64,63,0,0 monster Crocotree 1010,1,420000,240000
+000-1,31,69,0,0 monster Crocotree 1010,1,420000,240000
+000-1,44,44,0,0 monster Crocotree 1010,1,420000,240000
+000-1,70,33,0,0 monster Crocotree 1010,1,420000,240000
+000-1,84,66,0,0 monster Crocotree 1010,1,420000,240000
diff --git a/npc/000-1/_warps.txt b/npc/000-1/_warps.txt
new file mode 100644
index 00000000..47b4fb42
--- /dev/null
+++ b/npc/000-1/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-1: Drasil Island warps
+000-1,94,100,0 warp #000-1_94_100 0,0,000-2-0,21,28
diff --git a/npc/000-1/ale.txt b/npc/000-1/ale.txt
new file mode 100644
index 00000000..d7c6fed7
--- /dev/null
+++ b/npc/000-1/ale.txt
@@ -0,0 +1,109 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Sailor part of the Gugli's quest.
+// Aquada box.
+
+000-1,55,23,0 script Ale#000-1 NPC_DEMON_MAN_SITTING,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@g = getq(ShipQuests_Gugli);
+ if (.@g == 0) goto L_NoTask;
+
+ .@q = getq(ShipQuests_Ale);
+ if (.@q == 1) goto L_CallFunc;
+
+ mesn;
+ mesq l("Ouch...");
+ next;
+ mesq l("These heavy boxes are killing me, I can't feel my arms anymore!");
+ next;
+
+ menu
+ l("Gugli sent me down here to help you."), -,
+ l("See you aboard."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("Really? That's kind of you, I accept your help!");
+ next;
+ mesq l("Hmm... Let's see, take this one.");
+ next;
+
+ inventoryplace AquadaBox, 1;
+
+ setq ShipQuests_Ale, 1;
+ getitem AquadaBox, 1;
+
+ mes "";
+ mesn;
+ mesq l("I will take care of the other ones don't worry.");
+
+ close;
+
+L_CallFunc:
+ sailorfood;
+
+ menu
+ rif(getq(ShipQuests_Gugli) > 1, l("Task is done.")), L_TaskDone,
+ rif(getq(ShipQuests_Ale) == 1 && (getq(ShipQuests_Astapolos) == 0 || getq(ShipQuests_Gulukan) == 0 || getq(ShipQuests_Jalad) == 0 || getq(ShipQuests_QMuller) == 0 || getq(ShipQuests_Tibbo) == 0), l("I'm still busy, I need to find the other sailors.")), -;
+
+ mes "";
+ mesn;
+ mesq l("Who are you looking for?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Astapolos) == 0, l("Astapolos.")), L_Bottom,
+ rif(getq(ShipQuests_Gulukan) == 0, l("Gulukan.")), L_Bottom,
+ rif(getq(ShipQuests_Jalad) == 0, l("Jalad.")), L_Jalad,
+ rif(getq(ShipQuests_QMuller) == 0, l("Q'Muller.")), L_Bottom,
+ rif(getq(ShipQuests_Tibbo) == 0, l("Tibbo.")), L_Bottom,
+ l("Nobody."), L_Quit;
+
+L_Bottom:
+ mes "";
+ mesn;
+ mesq l("I've seen him down around the southern area of the island, ask Jalad for more information.");
+
+ close;
+
+L_Jalad:
+ setcamnpc "Jalad";
+
+ next;
+ mesn;
+ mesq l("Look, here he is!");
+ next;
+
+ restorecam;
+
+ close;
+
+L_NoTask:
+ mes "";
+ mesn;
+ mesq l("Ouch... These boxes are so heavy!");
+
+ close;
+
+L_TaskDone:
+ mes "";
+ mesn;
+ mesq l("That's good to hear!");
+
+ close;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/astapolos.txt b/npc/000-1/astapolos.txt
new file mode 100644
index 00000000..f28d7422
--- /dev/null
+++ b/npc/000-1/astapolos.txt
@@ -0,0 +1,165 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Sailor part of the Gugli's quest.
+// Croconut box.
+
+000-1,22,50,0 script Astapolos NPC_ELVEN_MAN_RED,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@g = getq(ShipQuests_Gugli);
+ if (.@g == 0) goto L_NoTask;
+
+ .@q = getq(ShipQuests_Astapolos);
+ if (.@q == 1) goto L_CallFunc;
+
+ mesn;
+ mesq l("So finally someone has came to visit me?");
+ next;
+
+ select
+ l("Actually, I came here to work on my task.");
+
+ mes "";
+ mesn;
+ mesq l("Oh, I see. That's right. Why should someone come here to see me, seriously?");
+ next;
+ mesq l("Do you think this is fair? They sent me down here alone, far away from everyone.");
+ next;
+
+ menu
+ l("I'm sorry for your situation. They should alternate shifts with other sailors from time to time."), -,
+ l("Well if you are whining like that all the time, then I think there is a reason behind their choice."), L_Whyning;
+
+ mes "";
+ mesn;
+ mesq l("Exactly. Even our task is ridiculous. Why should we collect food down here if we have plenty of those tasty and soft rattos inside our ship, waiting just to be hunted and cooked?");
+ next;
+
+ menu
+ l("You... You eat... rattos? I think you're just a fool."), L_Whyning,
+ l("Oh... eating rattos. Sounds... ehm... Delicious, yes."), -;
+
+ mes "";
+ mesn;
+ mesq l("You like them, don't you? Just speak with Peter then. He is on the second deck of the ship. He will send you downstairs to the hold, where you will find a furry meal!");
+ next;
+ mesq l("Oh, but you didn't come here to talk about that, am I right?");
+ next;
+
+ select
+ l("Actually, I was here to help you with those boxes. Can I bring one of them back to Gugli?");
+
+ mes "";
+ mesn;
+ mesq l("Usually I don't allow anyone to touch my boxes but...");
+ next;
+ mesq l("You have been so nice to me. So please, take one.");
+ next;
+
+ inventoryplace CroconutBox, 1;
+
+ setq ShipQuests_Astapolos, 1;
+ getitem CroconutBox, 1;
+
+ mes "";
+ mesn;
+ mesq l("Good luck! And remember to visit Peter and our little furry friends whenever you return back onboard!");
+
+ close;
+
+L_CallFunc:
+ sailorfood;
+
+ menu
+ rif(getq(ShipQuests_Gugli) > 1, l("Task is done.")), L_TaskDone,
+ rif(getq(ShipQuests_Astapolos) == 1 && (getq(ShipQuests_Ale) == 0 || getq(ShipQuests_Gulukan) == 0 || getq(ShipQuests_Jalad) == 0 || getq(ShipQuests_QMuller) == 0 || getq(ShipQuests_Tibbo) == 0), l("I'm still busy, I need to find the other sailors.")), -,
+ l("How are things going?"), L_HowAreYou,
+ l("Who are you?"), L_Who;
+
+ mes "";
+ mesn;
+ mesq l("Who are you looking for?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Ale) == 0, l("Ale.")), L_Top,
+ rif(getq(ShipQuests_Gulukan) == 0, l("Gulukan.")), L_Bottom,
+ rif(getq(ShipQuests_Jalad) == 0, l("Jalad.")), L_Top,
+ rif(getq(ShipQuests_QMuller) == 0, l("Q'Muller.")), L_Bottom,
+ rif(getq(ShipQuests_Tibbo) == 0, l("Tibbo.")), L_Bottom,
+ l("Nobody."), -;
+
+ closeclientdialog;
+ close;
+
+L_HowAreYou:
+
+ mes "";
+ mesn;
+ mesq l("A sunny and hot day,");
+ next;
+ mesq l("a quiet place,");
+ next;
+ mesq l("a ground!");
+ next;
+ mesq l("I hope that answers your question.") + " " + l("Hehe!");
+
+ close;
+
+L_Who:
+ mes "";
+ mesn;
+ mesq l("My name is Astapolos. Q'Muller and I joined Nard's crew a few years ago when it was just a little merchant ship.");
+ next;
+ mesq l("At that time, we were selling crab food on our old mushroom island.");
+ next;
+ mesq l("And now I'm a sailor, as you can see!");
+
+ close;
+
+L_Bottom:
+ mes "";
+ mesn;
+ mesq l("I've seen him at the southern part of the island, check around.");
+
+ close;
+
+L_Top:
+ mes "";
+ mesn;
+ mesq l("I've seen him at the northern part of the island.");
+ next;
+ mesq l("You should walk to the north.");
+
+ close;
+
+L_NoTask:
+ npctalk3 l("Just leave me alone.");
+
+ closeclientdialog;
+ close;
+
+L_TaskDone:
+ mes "";
+ mesn;
+ mesq l("Perfect!");
+
+ close;
+
+L_Whyning:
+ npctalk3 l("Then leave me alone.");
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/boss.txt b/npc/000-1/boss.txt
new file mode 100644
index 00000000..1b2f4449
--- /dev/null
+++ b/npc/000-1/boss.txt
@@ -0,0 +1,43 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Description:
+// Controls the boss on 000-1 and the Master Book Learning
+// see npc/items/master_skillbook.txt for explanation about variables
+
+000-1,0,0,0 script #BossCtrl_000-1 NPC_HIDDEN,{
+ end;
+
+// Test server: 15 minutes only
+OnTimer900000:
+ if (!debug)
+ end;
+
+// Otherwise, respawn every hour
+OnTimer3600000:
+ stopnpctimer;
+OnInit:
+ $@MB_0001=0;
+ monster "000-1", 87, 69, strmobinfo(1, Blub), Blub, 1, "#BossCtrl_000-1::OnBossDeath";
+ end;
+
+OnBossDeath:
+ initnpctimer;
+ BossSlain(.name$, "$@MB_0001");
+ end;
+
+OnBossCheck:
+ @mb_BossId=-1;
+ // TODO: Check if you really fought or was just lurking
+ // Check if party is correct
+ if (getcharid(1) != $@MB_0001)
+ end;
+OnBegin:
+ @mb_BossId=Blub;
+ @mb_SkillId=false;
+ @mb_ItemId=MagicFeather; // Placeholder
+ @mb_ItemAm=1;
+ addtimer(15000, "#MasterBook::OnUnset");
+ end;
+
+}
diff --git a/npc/000-1/chest.txt b/npc/000-1/chest.txt
new file mode 100644
index 00000000..511023e0
--- /dev/null
+++ b/npc/000-1/chest.txt
@@ -0,0 +1,65 @@
+// Evol scripts.
+// Authors:
+// 4144
+// gumi
+// Hal9000
+// Reid
+// Description:
+// A treasure chest, with... Treasures inside!
+// Variable:
+// x ShipQuests_TreasureChest
+// Values:
+// 0 Treasure Chest has not been opened yet.
+// 1 Treasure Chest has been opened.
+
+000-1,83,70,0 script Chest#000-1 NPC_CHEST,3,3,{
+
+ if (.busy == false)
+ {
+ if (getq(ShipQuests_TreasureChest) == 0)
+ {
+ inventoryplace OldBook, 1;
+ setq ShipQuests_TreasureChest, 1;
+ npctalk3 l("Chest opened.");
+ Zeny += 100;
+ getitem OldBook, 1;
+ }
+
+ specialeffect(.dir == 0 ? 24 : 25, AREA, getnpcid()); // closed ? opening : closing
+ .dir = .dir == 0 ? 2 : 6; // closed ? opening : closing
+ .busy = true; // lock until available again
+ initnpctimer;
+ }
+ end;
+
+OnTimer160:
+ .dir = .dir == 6 ? 0 : 4; // closing ? closed : open
+ end;
+
+OnTimer500:
+ .busy = false; // unlock
+
+ if (.dir == 0)
+ {
+ stopnpctimer; // stop here if the chest is closed
+ }
+ end;
+
+OnUnTouch:
+ if (getareausers(.x - 3, .y - 3, .x + 3, .y + 3) > 0 || .dir == 0)
+ {
+ end;
+ }
+OnTimer30000:
+ .busy = true;
+ .dir = 6; // closing
+ specialeffect(25, AREA, getnpcid()); // closing
+ setnpctimer 0;
+OnTouch:
+ end;
+
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/couwan.txt b/npc/000-1/couwan.txt
new file mode 100644
index 00000000..a4cdf6b8
--- /dev/null
+++ b/npc/000-1/couwan.txt
@@ -0,0 +1,94 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Couwan is trying to scam the player.
+// Variable:
+// x ShipQuests_Couwan
+// Values:
+// 0 Never talked with Couwan.
+// 1 Spoke, and received the quest scam.
+// 2 Done quest scam.
+
+000-1,89,36,0 script Couwan NPC_TRITAN_MAN_SAILOR,{
+ .@q = getq(ShipQuests_Couwan);
+ if (.@q == 1)
+ {
+ mesn;
+ mesq l("What are you looking at?");
+ next;
+ mesq l("Yeye still have my box? Stare less and work more. Go give it to Gugli!");
+ close;
+ }
+ else if (.@q > 1)
+ {
+ mesn;
+ mesq l("What are you looking at?");
+ next;
+ mesq l("Yeye gave my box to Gugli? Nice, nice yeye!");
+ close;
+ }
+
+ mesn;
+ mesq l("Hello yeye.");
+ next;
+ mesq l("Look how splendid this landscape is!");
+ next;
+
+ switch(select(
+ l("Very nice, indeed!"),
+ l("I don't see anything else other than... water?")))
+ {
+ case 2:
+ mes "";
+ mesn;
+ mesq l("Yeye's brain is probably still full of sea water if yeye can't see the beauty of this place.");
+ next;
+ mesq l("Stupid yeye...");
+ close;
+ }
+
+ mes "";
+ mesn;
+ mesq l("Yeye got good eyes and seem to have fully recovered from your injuries...");
+ next;
+ mesq l("Hey, could yeye please take my box of fish to Gugli?");
+ next;
+
+ switch(select(
+ l("Sure, but what will I get in exchange?"),
+ l("I'm sorry, I don't have time right now.")))
+ {
+ case 2:
+ mes "";
+ mesn;
+ mesq l("Stupid yeye...");
+ break;
+
+ case 255:
+ break;
+
+ default:
+ mes "";
+ mesn;
+ mesq l("Yeye ask too much but do too little. Take this box and stop talking.");
+ next;
+
+ inventoryplace FishBox, 1;
+ mesn "Narrator";
+ mesc(l("Couwan hands you a box full of fish."), 9);
+ getitem FishBox, 1;
+ next;
+ mesc(l("The sailor turns his back to you."), 9);
+
+ setq ShipQuests_Couwan, 1;
+ break;
+ }
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/darlin.txt b/npc/000-1/darlin.txt
new file mode 100644
index 00000000..e9f6649d
--- /dev/null
+++ b/npc/000-1/darlin.txt
@@ -0,0 +1,148 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Reid
+// Description:
+// Darlin talks from the top of the tall mast.
+// Variable:
+// x ShipQuests_TreasureChest
+// Values:
+// 0 Treasure Chest has not been opened yet.
+// 1 Treasure Chest has been opened.
+
+000-1,89,95,0 script Darlin NPC_RAIJIN_MAN,{
+ .@q = getq(ShipQuests_TreasureChest);
+
+ mesn;
+ setcamnpc;
+ mesq l("HEY! HEY YOU!");
+ next;
+ mesq l("CAN YOU HEAR ME?!");
+ next;
+ restorecam;
+
+ menu
+ l("Yes!"), -,
+ l("No!"), L_Quit;
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("GOOD!");
+ next;
+ mesq l("I WAS HERE WHEN THEY RESCUED YOU!");
+ next;
+ mesq l("DO YOU FEEL BETTER?!");
+ next;
+ restorecam;
+
+ menu
+ l("I do feel better!"), -,
+ l("Why don't you come down to talk?"), L_GoDown;
+
+ mes "";
+ menu
+ l("And you, how are you doing?"), -,
+ l("But I need to go, see you!"), L_Bye;
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("I AM DOING FINE!");
+ next;
+ mesq l("HEY, WHAT'S YOUR NAME?!");
+ next;
+ restorecam;
+
+ select
+ strcharinfo(0) + ".",
+ l("Maybe you can come down to talk?");
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("WHAT DID YOU SAY?!");
+ next;
+ mesq l("I DO NOT UNDERSTAND!");
+ next;
+ restorecam;
+
+ menu
+ l("I said... WHY DON'T YOU COME DOWN TO TALK?"), L_GoDown,
+ l("I SAID, SEE YOU LATER!"), L_Bye,
+ l("I'M CALLED, @@!", strtoupper(strcharinfo(0))), -;
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq strtoupper(strcharinfo(0)) + "? " + l("THAT'S A NICE NAME!");
+ next;
+ mesq l("SO WHAT'S UP?! WHAT ARE YOU DOING?!");
+ next;
+ restorecam;
+
+ menu
+ l("I'm looking for Gugli, where is he?"), -,
+ l("I need to go, sorry."), L_Bye;
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("OH, LOOK THERE!");
+ setcamnpc "Gugli";
+ next;
+ mesq l("HE IS AT THE BOTTOM OF THE SHIP, DOWN THE STAIRS. YOU CAN'T MISS HIM!");
+ next;
+ restorecam;
+
+ goto L_Quit;
+
+L_GoDown:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("I WOULD LOVE TO!");
+ next;
+ mesq l("BUT I CAN'T, I NEED TO KEEP AN EYE ON THE SEA, TO WARN THE CREW IF THERE HAPPENS TO BE SOME PIRATES AROUND!");
+ next;
+ mesq l("I ALSO AVOID THE DANGEROUS ANIMALS!");
+ next;
+ restorecam;
+
+ menu
+ l("Have you seen anything dangerous?"), -,
+ l("Interesting... I'll leave you to your task then!"), L_Bye;
+
+ mes "";
+ mesn;
+
+ if (.@q > 0) goto L_DangerAround;
+
+ setcamnpc;
+ mesq l("Oh no, but I've noticed a weird light on the other part of this island, I wonder what it could be...");
+ next;
+ restorecam;
+
+ goto L_Quit;
+
+L_Bye:
+ npctalk3 l("FINE, BYE!");
+
+ goto L_Quit;
+
+L_DangerAround:
+ setcamnpc;
+ mesq l("NOTHING ELSE OTHER THAN SHARKS AND AN ODD LIGHT!");
+ next;
+ restorecam;
+
+ goto L_Quit;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 14;
+ end;
+}
diff --git a/npc/000-1/fexil.txt b/npc/000-1/fexil.txt
new file mode 100644
index 00000000..7740263c
--- /dev/null
+++ b/npc/000-1/fexil.txt
@@ -0,0 +1,43 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Newbie merchant.
+
+000-1,83,98,0 script Fexil NPC_ELVEN_MAN_TRADER,{
+ mesn;
+ mesq l("Greetings traveler.");
+ next;
+ mesq l("I have some clothes and other things for you at a fine price!");
+ next;
+ mesq l("What I sell comes from every corner of Gasaron. From Esperia to the Land of Fire!");
+ next;
+ mesq l("Interested?");
+ next;
+
+ switch (select("Yes, why not.:I would rather sell some stuff.:No, Sorry."))
+ {
+ case 1:
+ mes "";
+ mesn;
+ mesq l("Good, take a look in the bag next to me then!");
+ close;
+
+ case 2:
+ closeclientdialog;
+ shop "Bag#000-1";
+ close;
+
+ default:
+ mes "";
+ mesn;
+ mesq l("Oh... Well, I just started to trade... Thus my technique may not be the best.");
+ next;
+ mesq l("Anyway, if you ever feel interested, just check my bag!");
+ close;
+ }
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/gugli.txt b/npc/000-1/gugli.txt
new file mode 100644
index 00000000..265deae6
--- /dev/null
+++ b/npc/000-1/gugli.txt
@@ -0,0 +1,248 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Elmo's twin
+// Charged of an important quest from Nard, he asks you to help other sailors to keep their box to the ship.
+// Variable:
+// 0 ShipQuests_Couwan
+// 1 ShipQuests_Nard
+// 2 ShipQuests_Gugli
+// Values:
+// 00 Never talked with Couwan.
+// 01 Spoke, and received the quest scam.
+// 02 Done quest scam.
+// 10 Introduction of the box and Nard. This is displayed when the player never spoke to Nard or his box.
+// 11 Nard spoke and gave access to the outdoor of the ship.
+// 12 Completed the quest.
+// 13 Opened the chest and finished the introduction.
+// 20 Never talked with Gugli.
+// 21 Gugli gives you the task.
+// 22 Gave all of the box to Gugli.
+
+000-1,85,108,0 script Gugli NPC_GUGLI,{
+
+ if (getq(ShipQuests_Couwan) == 1)
+ {
+ speech S_LAST_NEXT,
+ l("Great to see you! What can I do for you today?");
+ goto L_Menu;
+ }
+
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+OnTalk:
+ mesn;
+ .@nard = getq(ShipQuests_Nard);
+ .@gugli = getq(ShipQuests_Gugli);
+ .@gado = getq(ShipQuests_ChefGado);
+
+ if (.@nard > 3) goto L_AllComplete;
+ if (.@nard > 1 || .@gugli == 2) goto L_TaskCompleted;
+ if (.@gugli == 1) goto L_TaskGiven;
+
+ mesq l("Hi @@, I heard the captain sent you down here, uh?", strcharinfo(0));
+ next;
+ mesq l("What an unexpected pleasure, your help is always welcome!");
+ next;
+ mesq l("As you may know, we are explorers on a long distance voyage, and our swashbuckling mariners need to store enough food to survive. You don't know how dangerous the sea life can be.");
+ next;
+
+ select
+ l("Actually, I have an in-depth knowledge of this type of life.");
+
+ mes "";
+ mesn;
+ mesq l("Well, even though you have been rescued by us, it doesn't make you an expert sailor, am I right?");
+ next;
+ mesq l("But let's talk about this island. We're docking here to find some fine quality goods.");
+ next;
+ mesq l("We usually dock around these small isles because they provide us some of the best food of all the archipelago.");
+ next;
+ mesq l("At the moment, our crew is busy collecting @@s, @@s and @@s.", getitemlink(Croconut), getitemlink(Plushroom), getitemlink(Aquada));
+ next;
+
+ select
+ l("So, what can I do for you?");
+
+ mes "";
+ mesn;
+ mesq l("Right! Ours is an earthsea realm. You see, sailors are swift at their tasks when out of sight of land, but docked by this verdant jewel, they have it so good, they are just taking too much time bringing all the food back to the ship. Maybe you can help them.");
+ next;
+ mesq l("The captain wants:");
+ mesq l("- 2 @@es", getitemlink(AquadaBox));
+ mesq l("- 2 @@es", getitemlink(CroconutBox));
+ mesq l("- 2 @@es", getitemlink(PlushroomBox));
+ next;
+ mesq l("Ask sailors around here they shouldn't be so far away.");
+ next;
+
+ setq ShipQuests_Gugli, 1;
+ close;
+
+L_TaskGiven:
+ mesq l("Great to see you! What can I do for you today?");
+ next;
+
+ if (getq(ShipQuests_Ale) == 1 && getq(ShipQuests_Astapolos) == 1 && getq(ShipQuests_Gulukan) == 1 && getq(ShipQuests_Jalad) == 1 && getq(ShipQuests_QMuller) == 1 && getq(ShipQuests_Tibbo) == 1) goto L_MenuDone;
+
+L_Menu:
+ menu
+ rif(getq(ShipQuests_Couwan) == 1, l("Couwan gave me this box, it is for you.")), L_Couwan,
+ rif(countitem(AquadaBox) > 0 || countitem(CroconutBox) > 0 || countitem(PlushroomBox) > 0, l("I have some food for you.")), L_CollectSmthing,
+ rif(getq(ShipQuests_Gugli) < 2, l("Who should I search for?")), L_SailorNames,
+ rif(getq(ShipQuests_Gugli) < 2, l("Where can I find your crew?")), L_Location,
+ l("Bye!"), L_Quit;
+
+L_MenuDone:
+ menu
+ rif(getq(ShipQuests_Couwan) == 1, l("Couwan gave me this box, it is for you.")), L_Couwan,
+ l("I have collected all the boxes you needed."), L_TaskDone,
+ l("See you!"), L_Quit;
+
+L_SailorNames:
+ mes "";
+ mesn;
+ mesq l("Ale and Tibbo should bring 2 boxes of @@s, Astapolos and Gulukan 2 of @@s and Jalad and Q'Muller were charged of the boxes of @@s.", getitemlink(Aquada), getitemlink(Croconut), getitemlink(Plushroom));
+ next;
+ mesq l("Do you need any other information?");
+ next;
+
+ goto L_Menu;
+
+L_CollectSmthing:
+ mes "";
+ mesn;
+ mesq l("Good job!");
+ next;
+
+ delitem AquadaBox, countitem(AquadaBox);
+ delitem CroconutBox, countitem(CroconutBox);
+ delitem PlushroomBox, countitem(PlushroomBox);
+
+ mesq l("You still need to give me boxes from: ");
+ if (getq(ShipQuests_Astapolos) == 0) mesq l("- Astapolos");
+ if (getq(ShipQuests_Ale) == 0) mesq l("- Ale");
+ if (getq(ShipQuests_Gulukan) == 0) mesq l("- Gulukan");
+ if (getq(ShipQuests_Jalad) == 0) mesq l("- Jalad");
+ if (getq(ShipQuests_QMuller) == 0) mesq l("- Q'Muller");
+ if (getq(ShipQuests_Tibbo) == 0) mesq l("- Tibbo");
+
+ close;
+
+L_Couwan:
+ mes "";
+ mesn;
+ mesq l("What?! This tritan is the worse shirker I ever met!");
+ next;
+ mesq l("Well, thanks for the box. But... He was supposed to bring it back to me himself. I never asked him to give it to you!");
+ next;
+ mesq l("Take these coins in exchange and be careful.");
+ next;
+ mesq l("Not everybody has a kind mind. Scammers can be anywhere, even among us!");
+ next;
+ mesq l("May this be a lesson for you.");
+
+ if (countitem(FishBox) > 0) delitem FishBox, 1;
+ setq ShipQuests_Couwan, 2;
+ Zeny += 10;
+ getexp 40, 0;
+ message strcharinfo(0), l("You receive @@ E!", 10);
+
+ close;
+
+L_Location:
+ mes "";
+ mesn;
+ mesq l("There are 6 sailors who will need your help. They are all around the island.");
+ next;
+ mesq l("I can't really help you find them since I've been checking the... Hmm... Landscape, since morning...");
+ next;
+ mesq l("You can try talking with some other sailors to get some information about that.");
+ next;
+
+ .@r = rand(3000)/1000;
+ if (.@r == 1) goto L_Silvio;
+ if (.@r == 2) goto L_Lean;
+
+ setcamnpc "Sapartan";
+ mesq l("Maxe and Sapartan for example?");
+ next;
+
+ restorecam;
+ close;
+
+L_Silvio:
+ setcamnpc "Silvio";
+ mesq l("Silvio for example?");
+ next;
+
+ restorecam;
+ close;
+
+L_Lean:
+ setcamnpc "Lean";
+ mesq l("Lean for example?");
+ next;
+
+ restorecam;
+ close;
+
+L_TaskDone:
+ if (countitem(AquadaBox) == 2) delitem AquadaBox, 2;
+ if (countitem(CroconutBox) == 2) delitem CroconutBox, 2;
+ if (countitem(PlushroomBox) == 2) delitem PlushroomBox, 2;
+ if (countitem(AquadaBox) == 1) delitem AquadaBox, 1;
+ if (countitem(CroconutBox) == 1) delitem CroconutBox, 1;
+ if (countitem(PlushroomBox) == 1) delitem PlushroomBox, 1;
+ setq ShipQuests_Gugli, 2;
+
+ Zeny += 250;
+ getexp 50, 0;
+
+ mes "";
+ mesn;
+ mesq l("Well done! The ship is now ready to sail again!");
+ next;
+ mesq l("You should inform Nard of the progress made in loading food and supplies on to the boat. He will be pleased to hear that good news!");
+
+ close;
+
+L_TaskCompleted:
+ mesq l("You are now part of the crew... At least for us down here!");
+ next;
+ mesq l("You should inform Nard of the progress made in loading food and supplies on to the boat. He will be pleased to hear that good news!");
+ next;
+ mesq l("Tell him that everything went fine and that we're almost done with the requisitions.");
+ next;
+
+ goto L_Menu;
+
+L_AllComplete:
+ mesq l("Elmo told me what Nard said, congrats!");
+ next;
+ mesq l("You're one of us now, that's great! I was sure that you were a good person the first time I saw you!");
+ next;
+
+ goto L_Menu;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
+000-1,83,107,0 script GugliBarrierCheck NPC_HIDDEN,2,0,{
+ .@gugli = getq(ShipQuests_Gugli);
+ if (.@gugli > 0) close;
+ doevent "Gugli::OnTalk";
+ close;
+}
diff --git a/npc/000-1/gulukan.txt b/npc/000-1/gulukan.txt
new file mode 100644
index 00000000..0d80c932
--- /dev/null
+++ b/npc/000-1/gulukan.txt
@@ -0,0 +1,169 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Sailor part of the Gugli's quest.
+// Croconut box.
+
+000-1,54,90,0 script Gulukan NPC_TRITAN_MAN_SAILOR2,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@g = getq(ShipQuests_Gugli);
+ if (.@g == 0) goto L_NoTask;
+
+ .@q = getq(ShipQuests_Gulukan);
+ if (.@q == 1) goto L_Func;
+
+ mesn;
+ mesq l("Yeye @@!", strcharinfo(0));
+ next;
+ mesq l("How are you feeling, now that you walk on steady land? Yeye better?");
+ next;
+
+ menu
+ l("Wow, it seems everyone knows my name!"), -,
+ l("Well, it's not bad to finally feel something beneath my feet."), L_Continue,
+ l("Not so good actually... I would feel better on Nard's ship."), L_Quit;
+
+L_Name:
+ mes "";
+ mesn;
+ mesq l("You know, yeyes love to chat while working.");
+ next;
+
+goto L_Continue2;
+
+L_Continue:
+ mes "";
+ mesn;
+
+L_Continue2:
+ mesq l("Are you yaying here to explore the island?");
+ next;
+
+ menu
+ l("Actually Gugli asked me if I would help you bring him some of your boxes."), -,
+ l("Yes, indeed. I prefer to explore places I have never been to, before doing anything else."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("Gugli? Oh I see. Yes, Gugli yeye pretty used to shout orders to everybody down here.");
+ next;
+ mesq l("Anyway I am glad I can give you some of these yoyoxs.");
+ next;
+
+ inventoryplace CroconutBox, 1;
+
+ setq ShipQuests_Gulukan, 1;
+ getitem CroconutBox, 1;
+
+ mes "";
+ mesn;
+ mesq l("Thank you my friend.");
+
+ close;
+
+L_Func:
+ mesn;
+
+ .@q = rand(0, 400) / 100;
+ if (.@q == 0) goto L_RandomA;
+ if (.@q == 1) goto L_RandomB;
+ if (.@q > 1) goto L_RandomC;
+
+L_RandomA:
+ mesq l("Hey.");
+ next;
+ mesq l("What did Gugli yayaid about the box? Was it ok?");
+ next;
+
+ menu
+ l("It's ok."), L_Fine,
+ l("He needs more food."), -;
+
+ mes "";
+ mesn;
+ mesq l("Yeye sure? I'll yaye some more food in the next box then.");
+
+ close;
+
+L_Fine:
+ mes "";
+ mesn;
+ mesq l("Alright! Yoyone more box and it'll be good.");
+
+ close;
+
+L_RandomB:
+ mesq l("Thanks for the help!");
+ next;
+ mesq l("These yeye boxes are way too heavy to be carried alone onto the ship.");
+
+ close;
+
+L_RandomC:
+ mesq l("I think that yeye's soon be done. Yeye'll soon have a full box of @@s!", getitemlink(CrocClaw));
+ next;
+ mesq l("And you? How's it yaying on your side?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Gugli) > 1, l("Task is done.")), L_TaskDone,
+ rif(getq(ShipQuests_Gulukan) == 1 && (getq(ShipQuests_Ale) == 0 || getq(ShipQuests_Astapolos) == 0 || getq(ShipQuests_Jalad) == 0 || getq(ShipQuests_QMuller) == 0 || getq(ShipQuests_Tibbo) == 0), l("I'm still busy, I need to find the other sailors.")), -;
+
+ mes "";
+ mesn;
+ mesq l("Who are yeye looking for?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Ale) == 0, l("Ale.")), L_Top,
+ rif(getq(ShipQuests_Astapolos) == 0, l("Astapolos.")), L_Top,
+ rif(getq(ShipQuests_Jalad) == 0, l("Jalad.")), L_Top,
+ rif(getq(ShipQuests_QMuller) == 0, l("Q'Muller.")), L_Top,
+ rif(getq(ShipQuests_Tibbo) == 0, l("Tibbo.")), L_Bottom,
+ l("Nobody."), L_Quit;
+
+L_Bottom:
+ mes "";
+ mesn;
+ mesq l("Yeye seen this yoiis at the bottom of the island, check around.");
+
+ close;
+
+L_Top:
+ mes "";
+ mesn;
+ mesq l("Yeye seen this yoiis at the top of the island.");
+ next;
+ mesq l("You yoiis should walk to the north.");
+
+ close;
+
+L_NoTask:
+ mes "";
+ mesn;
+ mesq l("*Uff*... And another box of @@s for our starving colleagues is ready.", getitemlink(Croconut));
+
+ close;
+
+L_TaskDone:
+ mes "";
+ mesn;
+ mesq l("That's perfect, yoiis.");
+
+ close;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/jalad.txt b/npc/000-1/jalad.txt
new file mode 100644
index 00000000..43ba1f6e
--- /dev/null
+++ b/npc/000-1/jalad.txt
@@ -0,0 +1,130 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Sailor part of the Gugli quest.
+// Plushroom box.
+
+000-1,46,35,0 script Jalad NPC_ELVEN_MAN_TRADER_SITTING,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@g = getq(ShipQuests_Gugli);
+ if (.@g == 0) goto L_NoTask;
+
+ .@q = getq(ShipQuests_Jalad);
+ if (.@q == 1) goto L_CallFunc;
+
+ mesn;
+ mesq l("*Uff*, *Argh*, why don't you give me some help?");
+ next;
+ mesq l("I'm not suited for this kind of work!");
+ next;
+
+ menu
+ l("I was going to ask you if you would need any help."), L_Continue,
+ l("What exactly is your real job?"), -;
+
+ mes "";
+ mesn;
+ mesq l("I'm the cook's assistant of the ship. I help Gado, La Johanne's Chef, in his daily work.");
+ next;
+ mesq l("You should go see him. He is one of the most experienced sailors we have.");
+ next;
+
+ select
+ l("I will surely visit him. Do you need any help with your boxes?");
+
+L_Continue:
+ mes "";
+ mesn;
+ mesq l("Surely. Take this box full of @@s.", getitemlink(Plushroom));
+ next;
+
+ inventoryplace PlushroomBox, 1;
+
+ setq ShipQuests_Jalad, 1;
+ getitem PlushroomBox, 1;
+
+ mes "";
+ mesn;
+ mesq l("They are so tasty when cooked with some @@. Don't drop any of them!", getitemlink(PiouLegs));
+
+ goto L_Close;
+
+L_CallFunc:
+ sailorfood;
+
+ menu
+ rif(getq(ShipQuests_Gugli) > 1, l("Task is done.")), L_TaskDone,
+ rif(getq(ShipQuests_Jalad) == 1 && (getq(ShipQuests_Ale) == 0 || getq(ShipQuests_Astapolos) == 0 || getq(ShipQuests_Gulukan) == 0 || getq(ShipQuests_QMuller) == 0 || getq(ShipQuests_Tibbo) == 0), l("I'm still busy, I need to find the other sailors.")), -,
+ l("What's that?"), L_Plushroom;
+
+ mes "";
+ mesn;
+ mesq l("Who are you looking for?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Ale) == 0, l("Ale.")), L_Ale,
+ rif(getq(ShipQuests_Astapolos) == 0, l("Astapolos.")), L_Bottom,
+ rif(getq(ShipQuests_Gulukan) == 0, l("Gulukan.")), L_Bottom,
+ rif(getq(ShipQuests_QMuller) == 0, l("Q'Muller.")), L_Bottom,
+ rif(getq(ShipQuests_Tibbo) == 0, l("Tibbo.")), L_Bottom,
+ l("Nobody."), -;
+
+ closeclientdialog;
+ close;
+
+L_Bottom:
+ mes "";
+ mesn;
+ mesq l("I've seen him at the bottom of the island, have a look around.");
+
+ close;
+
+L_Ale:
+ setcamnpc "Ale";
+
+ next;
+ mesn;
+ mesq l("Look, there he is!");
+ next;
+
+ restorecam;
+ close;
+
+L_Plushroom:
+ mes "";
+ mesn;
+ mesq l("'That', as you call it, is a @@. There are plenty on this island!", getitemlink(Plushroom));
+ next;
+ mesq l("It's a kind of mushroom. We call it like that because of it's taste, just like a marshmallow. It also has this name because of it's appearance. It looks like a plush!");
+ next;
+ mesq l("There are some groups of these @@s all around this island. Just pick some and have a try.", getitemlink(Plushroom));
+
+ close;
+
+L_NoTask:
+ mes "";
+ mesn;
+ mesq l("Sometimes, I wish someone would be sent here to help us.");
+
+ close;
+
+L_TaskDone:
+ mes "";
+ mesn;
+ mesq l("Perfect!");
+
+L_Close:
+ goodbye;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/lean.txt b/npc/000-1/lean.txt
new file mode 100644
index 00000000..0cd3a1dd
--- /dev/null
+++ b/npc/000-1/lean.txt
@@ -0,0 +1,73 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Sailor who gives some informations to the player.
+
+000-1,79,108,0 script Lean NPC_ELVEN_MAN_BLONDE,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@gugli = getq(ShipQuests_Gugli);
+
+ mesn;
+ mesq l("Hi! I can finally see you under the sunlight!");
+ next;
+ mesq l("I hope you don't mind that we used your raft to build this ramp.");
+ next;
+ mesq l("We usually don't stop in such splendid places, but the captain let us stay here while he writes down the location of this new island on his map!");
+ next;
+ mesq l("Some of the crew are looking for goods we can trade with at our next destination.");
+ next;
+
+ menu
+ rif(.@gugli == 1, l("Well, I was in fact looking for them. Where are they now?")), L_Sailors,
+ l("Wait... Where are we going?"), L_Artis;
+
+L_Artis:
+ mes "";
+ mesn;
+ mesq l("Artis of course!");
+ next;
+ mesq l("It's where every merchant ship end their road and we won't be an exception.");
+ next;
+ mesq l("If you're looking for us there, most of us will be at the tavern of the Red Plush, at the bar counter, for Silvio's case...");
+
+ goto L_Close;
+
+L_Sailors:
+ mes "";
+ mesn;
+ mesq l("They are all around the island.");
+ next;
+ mesq l("I'm sure Tibbo is alone in the south-west corner of the island. He believes it's the best place to collect @@s.", getitemlink(Aquada));
+ next;
+ mesq l("While Jalad and Ale like to work together, as they usually do on the ship, last time I've seen them, they were near the big lake, north from here.");
+ next;
+ mesq l("They shouldn't be too far from each other.");
+ next;
+
+ menu
+ l("Thank you for your help."), L_Close,
+ l("Gugli mentioned six sailors. What about the others?"), -;
+
+ mes "";
+ mesn;
+ mesq l("I'm not sure. They probably left the ship early this morning. I was not awake yet.");
+ next;
+ mesq l("You should ask Maxe. He's an early riser.");
+
+ close;
+
+L_Close:
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/mapflags.txt b/npc/000-1/mapflags.txt
new file mode 100644
index 00000000..708dd2ab
--- /dev/null
+++ b/npc/000-1/mapflags.txt
@@ -0,0 +1 @@
+000-1 mapflag town
diff --git a/npc/000-1/maxe.txt b/npc/000-1/maxe.txt
new file mode 100644
index 00000000..f628c8c0
--- /dev/null
+++ b/npc/000-1/maxe.txt
@@ -0,0 +1,111 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Friend of Sapartan, he gives some information on how to find Gulukan, Astapolos and Q-Muller.
+
+000-1,72,110,0 script Maxe NPC_DEMON_MAN_SITTING_UNDER_TREE,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@gugli = getq(ShipQuests_Gugli);
+ .@knife = getq(ShipQuests_Knife);
+
+ mesn;
+ mesq l("We are glad captain Nard has let you join us down here!");
+ next;
+ mesq l("Living inside a ship is great, but we sometimes need some fresh air.");
+ next;
+ mesq l("Anyway, can I help you in any way?");
+ next;
+
+ menu
+ rif(.@gugli == 0, l("Well, is there anything I can do here to help?")), L_Help,
+ rif(.@gugli == 1, l("Gugli asked me to help the sailors to gather food. Do you know where I can find them?")), L_Sailors,
+ rif(.@gugli > 1, l("Seems I've helped everyone here. I don't know what to do now!")), L_Annoyed,
+ rif(.@knife == 0, l("It looks like you are an expert of the life inside 'La Johanne'. Do you know any hidden secrets nobody knows?")), L_Secrets,
+ l("No thanks, not at the moment."), L_Quit;
+
+L_Help:
+ mes "";
+ mesn;
+ mesq l("You could start by talking to Gugli. He always has tasks for people willing to help!");
+
+ close;
+
+L_Sailors:
+ mes "";
+ mesn;
+ mesq l("I remember I saw a few of them leaving the ship early this morning to get a head start on today's work.");
+ next;
+ mesq l("I recall seeing Gulukan, Astapolos and Q'Muller.");
+ next;
+
+ goto L_MenuSailors;
+
+L_MenuSailors:
+ menu
+ l("Do you know where can I find Gulukan?"), L_Gulukan,
+ l("Any clue on where Astapolos may be hidden?"), L_Astapolos,
+ l("What about Q'Muller? Where is he?"), L_Qmuller,
+ l("Alright. I will go looking for them now."), L_Quit;
+
+L_Gulukan:
+ mes "";
+ mesn;
+ mesq l("Oh, he is not far away from here. Just take the road through the crocojungle north from here.");
+ next;
+ mesq l("You will find a wooden sign near a crossroad. He is a few steps on the left.");
+ next;
+
+ goto L_MenuSailors;
+
+L_Astapolos:
+ mes "";
+ mesn;
+ mesq l("Astapolos... That guy is shy like a piou!");
+ next;
+ mesq l("He likes to hide near the little lake in the north-west side of the island.");
+ next;
+
+ goto L_MenuSailors;
+
+L_Qmuller:
+ mes "";
+ mesn;
+ mesq l("You need to cross the crocojungle heading north.");
+ next;
+ mesq l("You can spot Q'Muller on a cliff off toward the west, busy collecting @@s.", getitemlink(Plushroom));
+ next;
+
+ goto L_MenuSailors;
+
+L_Annoyed:
+ mes "";
+ mesn;
+ mesq l("There is always something you can do here, like killing some tortugas or helping Peter clean the ship from rattos.");
+
+ close;
+
+L_Secrets:
+ mes "";
+ mesn;
+ mesq l("Nope, there are no secrets hidden within the ship's hull. Some sailors swear they have seen stowaways hidden somewhere. The bow or the stern? Just stories sailors love to tell...");
+ next;
+ mesq l("Oh! And in one of the rooms of the second deck you can find Gado's knives. Our chef keeps there the sharpest ones... Probably not just to cut some carrots...");
+ next;
+ mesq l("Go and grab one of them. A good knife will help with your hunting the creatures of this island.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+
+L_Quit:
+ goodbye;
+}
diff --git a/npc/000-1/muller.txt b/npc/000-1/muller.txt
new file mode 100644
index 00000000..0d13ff0d
--- /dev/null
+++ b/npc/000-1/muller.txt
@@ -0,0 +1,131 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Reid
+// Description:
+// Sailor part of the Gugli's quest.
+// Plushroom box.
+
+000-1,35,69,0 script Q'Muller NPC_ORC_MAN,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@g = getq(ShipQuests_Gugli);
+ if (.@g == 0) goto L_NoTask;
+
+ .@q = getq(ShipQuests_QMuller);
+ if (.@q == 1) goto L_CallFunc;
+
+ mesn;
+ mesq l("Can't you see I'm working?!");
+ next;
+
+ select
+ l("Well I'm working too! Don't you want me to carry one of these boxes back to Gugli?");
+
+ mes "";
+ mesn;
+ mesq l("Oh I see... Sailors are not able to do their job anymore, is it like that?!");
+ next;
+
+ menu
+ l("Indeed! Goodbye."), L_Quit,
+ l("Yes, it is true! You are not able at all. Nard has been waiting for the food for too long already. Hurry up, you lazy sailors!"), -;
+
+ mes "";
+ mesn;
+ mesq l("Are you blind? Do you really think these boxes are light and soft as a piou's feather?!");
+ next;
+
+ select
+ l("I am sure that I can run with one of them on my shoulder.");
+
+ mes "";
+ mesn;
+ mesq l("Well then... Take this one!");
+ next;
+
+ inventoryplace PlushroomBox, 1;
+
+ setq ShipQuests_QMuller, 1;
+ getitem PlushroomBox, 1;
+
+ mes "";
+ mesn;
+ mesq l("And now I want to see you run!");
+
+ close;
+
+L_CallFunc:
+ sailorfood;
+
+ menu
+ rif(getq(ShipQuests_Gugli) > 1, l("Task is done.")), L_TaskDone,
+ rif(getq(ShipQuests_QMuller) == 1 && (getq(ShipQuests_Ale) == 0 || getq(ShipQuests_Astapolos) == 0 || getq(ShipQuests_Gulukan) == 0 || getq(ShipQuests_Jalad) == 0 || getq(ShipQuests_Tibbo) == 0), l("I'm still busy, I need to find the other sailors.")), -,
+ l("What's that?"), L_Plushroom;
+
+ mes "";
+ mesn;
+ mesq l("Who are you looking for?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Ale) == 0, l("Ale.")), L_Top,
+ rif(getq(ShipQuests_Astapolos) == 0, l("Astapolos.")), L_Top,
+ rif(getq(ShipQuests_Jalad) == 0, l("Jalad.")), L_Top,
+ rif(getq(ShipQuests_Gulukan) == 0, l("Gulukan.")), L_Bottom,
+ rif(getq(ShipQuests_Tibbo) == 0, l("Tibbo.")), L_Bottom,
+ l("Nobody."), L_Quit;
+
+L_Bottom:
+ mes "";
+ mesn;
+ mesq l("I've seen him at the bottom of the island, check around.");
+
+ close;
+
+L_Top:
+ mes "";
+ mesn;
+ mesq l("I've seen him at the top of the island.");
+ next;
+ mesq l("You should walk to the north.");
+
+ close;
+
+L_Plushroom:
+ mes "";
+ mesn;
+ mesq l("'That', as you call it, is a @@. There are plenty on this island!", getitemlink(Plushroom));
+ next;
+ mesq l("It's a kind of mushroom. We call it like that because of it's taste, just like a marshmallow. It also has this name because of it's appearance, it looks like a plush!");
+ next;
+ mesq l("There are few groups of these @@s all around this island. Just pick some and have a try.", getitemlink(Plushroom));
+
+ close;
+
+L_NoTask:
+ mes "";
+ mesn;
+ mesq l("You see? I'm working here!");
+
+ close;
+
+L_TaskDone:
+ mes "";
+ mesn;
+ mesq l("Good to hear!");
+ next;
+
+ goodbye;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/panels.txt b/npc/000-1/panels.txt
new file mode 100644
index 00000000..93f25beb
--- /dev/null
+++ b/npc/000-1/panels.txt
@@ -0,0 +1,54 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Qwerty Dragon
+// Description:
+// Panels to give advice to the players.
+
+000-1,65,93,0 script #panel1 NPC_NO_SPRITE,{
+ mesn "Narrator";
+ mesc(l("Your heart quickens as your gaze focuses upon a small wooden panel, partly obscured under a layer of wind-blown sand."), 9);
+ next;
+ mesc(l("You wipe off enough of the sand to manage to read the message written on this crude piece of wood."), 9);
+ next;
+ mesq l("It's a dangerous place out here. Beware of the mischievous creatures living here!");
+ next;
+ mesq l("Not content to stay buried in their burrows in the sand, Crocs can be quite a nuisance, infesting this whole island. Tender Feet and Newbies are advised: Avoid touching these crawling red devils. They have huge, deadly claws that can make mincemeat of you! You can recognize them easily by their crabby personalities. Be careful younglings.");
+ next;
+ mesq l("Furthermore, unless you are planning to stick it out, you should also not even think about gaining experience by messing with those icky pink land jellies. The pink could stick on you, imagine the horror!");
+ next;
+ mesq l("In fact... Oh, the things that I could tell... But ran out of space on this... Just be reasonable and go home.");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
+000-1,89,51,0 script #panel2 NPC_NO_SPRITE,{
+ mesn "Narrator";
+ mesc(l("This panel looks in rather good shape, as though some people take care of it regularly. Maybe it has important information."), 9);
+ next;
+ mesc(l("You can read some lines that are nicely carved into the soft wooden planks."), 9);
+ next;
+ mesq l("The further you go, the more experience you will get, so here's a small description of all the stats you can upgrade with time. But note that these will probably change in the future and have more complex effects.");
+ next;
+ mesq l("Strength multiplies the damage of your hits, especially melee ones. You will also be able to carry heavier stuff.");
+ next;
+ mesq l("Agility greatly increases your attack speed and the chances of you dodging enemy hits.");
+ next;
+ mesq l("Vitality raises your maximum health points and defense.");
+ next;
+ mesq l("Intelligence raises your maximum mana points (good for mages) and your mind abilities. Please note: Magic system has not yet been implemented in this world.");
+ next;
+ mesq l("Dexterity increases your bow damage and your accuracy.");
+ next;
+ mesq l("Luck helps you do critical hits and dodge the ones dealt by enemies.");
+ next;
+ mesq l("Have fun, but always remember to pick your stats with good care.");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/sapartan.txt b/npc/000-1/sapartan.txt
new file mode 100644
index 00000000..5e33a086
--- /dev/null
+++ b/npc/000-1/sapartan.txt
@@ -0,0 +1,101 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Description:
+// Friend of Maxe, he gives some information on combat system.
+
+000-1,74,111,0 script Sapartan NPC_SAPARTAN,{
+ mesn;
+ mesq l("Hey Maxe, it's @@!", strcharinfo(0));
+ next;
+
+ setcamnpc "Maxe";
+ mesn "Maxe";
+ mesq l("@@? Welcome my dear!", strcharinfo(0));
+ next;
+ mesq l("Last time I saw you, you were lost at sea on your raft.");
+ next;
+ restorecam;
+
+ mesn;
+ mesq l("True but now all seems pretty fine! Am I right?");
+ next;
+
+ menu
+ l("Thank you, sir, for your kind words. I am feeling better now."), -,
+ l("I'm still a bit weak at the moment. We should probably talk later."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("You can now stay with your new friends and enjoy the warm sand of this little island.");
+ next;
+ mesq l("But remember that not every place in this world is peaceful and safe nowadays. Even the white shores you are walking on can hide some dangerous beings.");
+ next;
+
+ select
+ l("What danger?! Where?!");
+
+ setcamnpc "Maxe";
+ mes "";
+ mesn "Maxe";
+ mesq l("Come on, Sap! Do not always scare others with your horror stories.");
+ next;
+ mesq l("I'm sure this brave fellow will soon be able to fight all of the creatures living here without any problem.");
+ next;
+
+ restorecam;
+
+ mes "";
+ mesn;
+ mesq l("Maybe... But I prefer having well-trained people around me when it comes to fighting against dangerous creatures. Do you already feel adept fighting enemies?");
+ next;
+
+ menu
+ l("No, I don't, but I would like to know more about that."), -,
+ l("Well... I've only killed some little pious in the ship, that's all."), -,
+ l("Yes, I feel strong enough for dangerous combats!"), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("Then I can give you some tips about fighting.");
+ next;
+ mesq l("The first thing you should do is to evaluate your enemy.");
+ next;
+ mesq l("You can easily see if a monster is easy to kill or just impossible to defeat. Do not try against creatures that are way more powerful than you... You'd be risking your life for nothing.");
+ next;
+ mesq l("Secondly, choose wisely which weapon is suited for you. Some people like to face their enemies closely with a heavy axe, others prefer to attack from a distance with a bow for example.");
+ next;
+
+ select
+ l("Yeah, well what's the difference?");
+
+ mes "";
+ mesn;
+ mesq l("On one hand, ranged weapons are generally weaker than melee ones, but you attack from a safer position. On the other hand, depending on the level of the weapon, melee ones potentially can yeild quicker kills.");
+ next;
+ mesq l("After choosing your weapon, you also need to know how to use it.");
+ next;
+ mesq l("You can attack a monster by clicking directly on it. Once selected, you may notice a bar near your target showing you how much health it has left.");
+ next;
+ mesq l("You can also attack an enemy from your keyboard pressing the 'A' key to select it, and the 'Ctrl' key to attack it, this of course works if you didn't change your keyboard keys yet.");
+ next;
+
+ menu
+ l("Thank you for your tricks. I am going to try them now!"), -,
+ l("I already know everything. Bye."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("You're welcome. If you can't remember something, just come back here!");
+ next;
+
+ goodbye;
+
+OnInit:
+ .distance = 2;
+ end;
+
+L_Quit:
+ goodbye;
+}
diff --git a/npc/000-1/shop.txt b/npc/000-1/shop.txt
new file mode 100644
index 00000000..be588e99
--- /dev/null
+++ b/npc/000-1/shop.txt
@@ -0,0 +1,32 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Fexil's shop bag.
+
+000-1,84,98,0 trader Bag#000-1 NPC_SHOP_BAG,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem PiouLegs, -1, 15;
+ sellitem Bread, -1, 15;
+ sellitem Croconut, -1, 50;
+ sellitem Aquada, -1, 50;
+ sellitem Armbands, -1, 20;
+ sellitem LousyMoccasins, -1, 20;
+ sellitem PiouSlayer, -1, 15;
+
+ .distance = 3;
+ end;
+
+OnClock0000:
+ restoreshopitem PiouLegs, 15;
+ restoreshopitem Bread, 15;
+ restoreshopitem Croconut, 50;
+ restoreshopitem Aquada, 50;
+ restoreshopitem Armbands, 20;
+ restoreshopitem LousyMoccasins, 20;
+ restoreshopitem PiouSlayer, 15;
+}
diff --git a/npc/000-1/silvio.txt b/npc/000-1/silvio.txt
new file mode 100644
index 00000000..ec5669d3
--- /dev/null
+++ b/npc/000-1/silvio.txt
@@ -0,0 +1,185 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Perverted and arrogant sailor.
+
+000-1,86,99,0 script Silvio NPC_SILVIO,{
+ mesn;
+ mesq l("Hey!");
+ next;
+ mesq l("How are you doing?");
+ next;
+
+ menu
+ l("Hello... Do I know you?"), -,
+ rif(getq(ShipQuests_Gugli) > 0 && getq(General_Narrator) == 0, l("Fine, could you please tell me where I can find Gugli's sailors?")), L_Sailors,
+ l("Uhm, bye."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("Hehe, no. But I'm sure somebody like you would love to meet somebody like me! Women want me, men want to be like me!");
+ next;
+ mesq l("So, what good wind brought you here? Were you on your raft to meet me or Julia? Or is it because you've heard of my feats in Artis?");
+ next;
+
+ menu
+ l("You're right, it's about you."), L_Julia,
+ l("What is Artis?"), L_Artis,
+ l("None of them?"), -;
+
+ mes "";
+ mesn;
+ mesq l("You know that I was not always a sailor, right? I was once a very important Person!");
+ next;
+ mesq l("Before...");
+ next;
+
+ setcamnpc "Gugli";
+ mes "";
+ mesn "Gugli";
+ mesq l("Hey, don't worry about him, it's one of the first days in a long time that we can just chill out.");
+ next;
+ mesq l("Maybe he over did it with the bottle today to celebrate that!");
+ next;
+ restorecam;
+
+ menu
+ l("He's funny, it's not a problem."), -,
+ l("Ok, I will leave him alone."), L_ForeverAlone;
+
+ setcamnpc "Gugli";
+ mes "";
+ mesn "Gugli";
+ mesq l("Oh alright, nevermind then.");
+ next;
+ restorecam;
+
+ mesn;
+ mesq l("Ah... Gugli... He's too young to understand our conversation.");
+ next;
+ mesq l("So, what was I saying?");
+ next;
+
+ menu
+ l("You told me that you 'were' important."), L_VeryImportantNoob,
+ l("You mentioned the quality of your wine."), -;
+
+ mes "";
+ mesn;
+ mesq l("Oh really? How could I forget something as important as that?!");
+ next;
+ mesq l("I think that my wine is of great quality! I'm on my second bottle and I already... What were we talking about again?");
+
+ close;
+
+L_VeryImportantNoob:
+ mes "";
+ mesn;
+ mesq l("It's true!");
+ next;
+ mesq l("But I can't tell you anything about it, I'm sorry.") ;
+ next;
+
+ setcamnpc "Gugli";
+ mes "";
+ mesn "Gugli";
+ mesq l("Hey Silvio, it's your turn to carry the package, go!");
+ next;
+ restorecam;
+
+ mesn;
+ mesq l("Duty calls me, *hic*, see you later.");
+
+ close;
+
+L_Julia:
+ mes "";
+ mesn;
+ mesq l("Not to kill your dreams, but i fear me and Julia are romantically entangled and there is no room for a third person ... on the other hand *smirks frivolous*");
+ next;
+ mesq l("She said she will accept me when pious will have teeth. It's just a matter of time, you see?");
+ next;
+
+ menu
+ l("I see. Bye!"), L_Quit,
+ l("Oh look, there's a piou behind you!"), L_Piou;
+
+L_Piou:
+ mes "";
+ mesn;
+ mesq l("Seriously?!");
+ next;
+ mesq l("Hurry, hurry! We need to check its teeth!");
+
+ close;
+
+L_Artis:
+ mes "";
+ mesn;
+ mesq l("Artis is a very nice place. There are some hot chicks...");
+ next;
+ mesq l("The Raijin from the library flirted with me a while ago, so has Enora from the Legion.");
+ next;
+ mesq l("Oh, and Olga from the marketplace as well!");
+ next;
+ mesq l("You should look for them when we arrive at the port. You won't regret it! Ehehe...");
+
+ goodbye;
+
+L_ForeverAlone:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Silvio starts to speak to his bottle, you leave, letting him have a private conversation."), 9);
+
+ close;
+
+L_Sailors:
+ mes "";
+ mesn;
+ mesq l("What? Why? They aren't more attractive than me, why do you want to see them?");
+ next;
+ mesq l("And what would you give me in exchange for that information?");
+ next;
+
+ setcamnpc "Gugli";
+ mes "";
+ mesn "Gugli";
+ mesq l("Stop heckling, Silvio, or I'll tell about how you always cry like a little baby during thunderstorms.");
+ next;
+ restorecam;
+
+ mesn;
+ mesq l("I...");
+ next;
+ mesq l("How could you... We said we wouldn't talk about that again!");
+ next;
+ mesq l("Tibbo went to the south-east of the island, others are gone to the north, and I think that Gulukan is not so far from here.");
+ next;
+ mesq l("But anyway, take the road which goes to the north to find everybody.");
+ next;
+ mesq l("Now, leave me alone...");
+ next;
+
+ menu
+ l("See you."), L_Quit,
+ l("*Imitate a thunder's sound.*"), -;
+
+ closeclientdialog;
+
+ npctalk3 l("Aaaaaahhhhhh!");
+
+ close;
+
+L_Quit:
+ closeclientdialog;
+
+ npctalk3 l("Give me a kiss before you say goodbye!");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/tarlan.txt b/npc/000-1/tarlan.txt
new file mode 100644
index 00000000..fad4be2a
--- /dev/null
+++ b/npc/000-1/tarlan.txt
@@ -0,0 +1,64 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Sailor hitting a crocotree, then being struck by a falling croconut.
+
+000-1,33,37,0 script Tarlan NPC_TARLAN,{
+ .dir = 2;
+
+ mesn;
+ .@a = rand(4);
+ if (.@a == 0) goto L_HardToHit;
+ if (.@a == 1) goto L_Aouch;
+ if (.@a == 2) goto L_DoYou;
+
+ mesq l("Hey you!");
+ next;
+ mesq l("What are you looking for?");
+ next;
+
+ menu
+ l("Some food."), L_Food,
+ l("Nothing, just hanging around."), -;
+
+ closeclientdialog;
+ npctalk3 l("Ok, see you then!");
+ goto L_Quit;
+
+L_Food:
+ mes " ";
+ mesn;
+ mesq l("You can yaye some @@s by hitting these crocotrees.", getitemlink(Croconut));
+ next;
+ mesq l("Yeye be careful with wild animal's food, some of them are yeyery dangerous, especially the crocs.");
+
+ goto L_Quit;
+
+L_HardToHit:
+ mesq l("These crocotrees are full of yaying @@s, but they are so hard to hit...", getitemlink(Croconut));
+
+ goto L_Quit;
+
+L_Aouch:
+ mesq l("Ayouyouch! My head...");
+ next;
+ mesq l("Damn @@.", getitemlink(Croconut));
+
+ goto L_Quit;
+
+L_DoYou:
+ mesq l("Do you want to try?");
+ next;
+ mesq l("Just hit the trunk, and it will yeye a @@.", getitemlink(Croconut));
+
+ goto L_Quit;
+
+L_Quit:
+ .dir = 4;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-1/tibbo.txt b/npc/000-1/tibbo.txt
new file mode 100644
index 00000000..89c82f11
--- /dev/null
+++ b/npc/000-1/tibbo.txt
@@ -0,0 +1,122 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// Sailor part of the Gugli's quest.
+// Aquada box.
+
+000-1,34,111,0 script Tibbo NPC_ELVEN_MAN_STANDING,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ .@g = getq(ShipQuests_Gugli);
+ if (.@g == 0) goto L_NoTask;
+
+ .@q = getq(ShipQuests_Tibbo);
+ if (.@q == 1) goto L_CallFunc;
+
+ mesn;
+ mesq l("Uh? Hi! I'm sorry, but I have no time for chatting.");
+ next;
+
+ select
+ l("Fine... I was just going to give you some help...");
+
+ mes "";
+ mesn;
+ mesq l("Hel... What?! Wait!");
+ next;
+ mesq l("What kind of help?");
+ next;
+
+ select
+ l("Gugli asked me to help you carrying one of these boxes you are filling.");
+
+ mes "";
+ mesn;
+ mesq l("Then it seems I have to apologize.");
+ next;
+ mesq l("I am surprised someone has been sent here to help. It is quite... unusual.");
+ next;
+ mesq l("Bring this box to Gugli. He will be extremely happy!");
+ next;
+
+ inventoryplace AquadaBox, 1;
+
+ setq ShipQuests_Tibbo, 1;
+ getitem AquadaBox, 1;
+
+ mes "";
+ mesn;
+ mesq l("Thank you and be careful with that box. I have worked really hard to fill it!");
+
+ goto L_Close;
+
+L_CallFunc:
+ sailorfood;
+
+ menu
+ rif(getq(ShipQuests_Gugli) > 1, l("Task is done.")), L_TaskDone,
+ rif(getq(ShipQuests_Tibbo) == 1 && (getq(ShipQuests_Ale) == 0 || getq(ShipQuests_Astapolos) == 0 || getq(ShipQuests_Gulukan) == 0 || getq(ShipQuests_Jalad) == 0 || getq(ShipQuests_QMuller) == 0), l("I'm still busy, I need to find the other sailors.")), -,
+ l("What's that food?"), L_Aquada;
+
+ mes "";
+ mesn;
+ mesq l("Who are you looking for?");
+ next;
+
+ menu
+ rif(getq(ShipQuests_Ale) == 0, l("Ale.")), L_Top,
+ rif(getq(ShipQuests_Astapolos) == 0, l("Astapolos.")), L_Top,
+ rif(getq(ShipQuests_Gulukan) == 0, l("Gulukan.")), L_Top,
+ rif(getq(ShipQuests_Jalad) == 0, l("Jalad.")), L_Top,
+ rif(getq(ShipQuests_QMuller) == 0, l("Q'Muller.")), L_Top,
+ l("Nobody."), -;
+
+ goto L_Close;
+
+L_Top:
+ mes "";
+ mesn;
+ mesq l("I've seen him at the top of the island.");
+ next;
+ mesq l("You should walk to the north to find him.");
+
+ close;
+
+L_Aquada:
+ mes "";
+ mesn;
+ mesq l("This is an @@, a light blue sea fruit. They're highly desired in the archipelago.", getitemlink(Aquada));
+ next;
+ mesq l("You can find them in the ocean, near corals and other sea beings. But the sea is too heavy today, you shouldn't try swimming for now.");
+ next;
+ mesq l("Otherwise, if you really want one, and if you feel capable, you can try killing tortugas or crocs if you're strong enough. I'm sure they could drop one or two @@s.", getitemlink(Aquada));
+
+ close;
+
+L_NoTask:
+ mes "";
+ mesn;
+ mesq l("I'm sorry but I have no time to chat with you.");
+
+ close;
+
+L_TaskDone:
+ mes "";
+ mesn;
+ mesq l("Awesome!");
+
+ close;
+
+L_Close:
+ goodbye;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-0/_import.txt b/npc/000-2-0/_import.txt
new file mode 100644
index 00000000..c0b9afb1
--- /dev/null
+++ b/npc/000-2-0/_import.txt
@@ -0,0 +1,8 @@
+// Map 000-2-0: First Deck
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-2-0/_warps.txt",
+"npc/000-2-0/billybons.txt",
+"npc/000-2-0/doors.txt",
+"npc/000-2-0/julia.txt",
+"npc/000-2-0/mapflags.txt",
+"npc/000-2-0/note.txt",
diff --git a/npc/000-2-0/_warps.txt b/npc/000-2-0/_warps.txt
new file mode 100644
index 00000000..5496ecae
--- /dev/null
+++ b/npc/000-2-0/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-0: First Deck warps
+000-2-0,31,25,0 warp #000-2-0_31_25 0,0,000-2-1,72,29
diff --git a/npc/000-2-0/billybons.txt b/npc/000-2-0/billybons.txt
new file mode 100644
index 00000000..cfdfd7af
--- /dev/null
+++ b/npc/000-2-0/billybons.txt
@@ -0,0 +1,95 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Drunk easteregg telling about the player's past.
+
+000-2-0,20,23,0 script Billy Bons NPC_BILLY_BONS,{
+ if (rand(5) == 2) goto L_Hic;
+
+ mesn;
+ mesq l("You? Here?");
+ mesq l("How is *hic* it possible?");
+ next;
+
+ mesn "Narrator";
+ mesc(l("The sailor chugs his beer."), 9);
+ next;
+
+ select
+ l("Excuse me? Do you know who I am?");
+
+ mes "";
+ mesn;
+ mesq l("Don't do theee... *hic* with me eh!");
+ next;
+
+ menu
+ l("Are you ok?"), L_Quit,
+ l("Alright... Bye."), -;
+
+ mes "";
+ mesn;
+ mesq l("No and *hic*... No, you and you and your... *burp* stup*hic* guild!");
+ next;
+ mesq l("You tried to get rid of me, eeh? But surprise! I'm still here... *hic* Or there...");
+ next;
+ mesq l("But you won't *hic* me this time...");
+ next;
+
+ menu
+ l("What are you talking about? What guild?"), L_Quit,
+ l("You are full of wine, my friend..."), -,
+ l("You should go and get some sleep."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("If I saw *hic* who you were... *hic* Would not have helped you! ");
+ next;
+
+ menu
+ l("But who am I?"), -,
+ l("What am I supposed to say?"), L_Quit,
+ l("You should go and get some sleep."), L_Secret;
+
+ mes "";
+ mesn;
+ mesq l("The giant boogeyman!");
+
+ close;
+
+L_Secret:
+ mes "";
+ mesn;
+ mesq l("Hear me *hic* well, what ever, whatididever you will *hic* said ab... uhm... out what?! You saw there, the Legion of Aemil won't let it get public.");
+ next;
+ mesq l("Nobody will know about the existence of the Mercurians.");
+ next;
+ mesq l("Nobody! *burp*");
+ next;
+
+ close;
+
+L_Hic:
+ npctalk3 l("*Hic*");
+
+ close;
+
+L_Quit:
+ mes "";
+ mesn;
+ mesq l("Yeah you're all like *hic* that in Esperia, but you won't get me! *burp*");
+ next;
+ mesq l("I'm not that numb eeh *hic* what did ever yous disco... ...vered there, the Legion of Aemil won't get me!");
+ mesq l("*burp*");
+ next;
+
+ mesn "Narrator";
+ mesc(l("The sailor turns his back to you."), 9);
+
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/000-2-0/doors.txt b/npc/000-2-0/doors.txt
new file mode 100644
index 00000000..ee29340a
--- /dev/null
+++ b/npc/000-2-0/doors.txt
@@ -0,0 +1,85 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Doors NPCs.
+// The third value of the .@nard variable has been removed for the beta2, it'll then be re-added for the Aurora release.
+// Variable:
+// 0 ShipQUests_Nard
+// 1 ShipQuests_Julia
+// Values:
+// Nard:
+// 00 Introduction of the boxes and Nard. This is displayed when the player never spoke to Nard or his box.
+// 01 Nard spoke and gave access to the outdoor of the ship.
+// 02 Completed the Gugli quest.
+// 03 ChefGado Quest accepted.
+// 04 ChefGado Quest completed and "Introduction" chapter finalized.
+// 05 Reward taken from the box.
+// 10 Has not talked to Julia
+// 11 Need to see Julia
+// 12 Has been registered by Julia
+
+000-2-0,19,28,0 script AreaNPC#doors1 NPC_HIDDEN,0,0,{
+
+OnTouch:
+ .@nard = getq(ShipQuests_Nard);
+
+ if (getq(General_Narrator) > 0)
+ {
+ warp "000-1", 93, 100;
+ close;
+ }
+
+ if (.@nard == 4) goto L_GotoNard;
+ if (.@nard == 5) goto L_End;
+ if (.@nard > 0 && countitem(718) > 0) goto L_Key;
+
+ setcamnpc "Julia";
+ mesn "Julia";
+ mesq l("The captain has locked the door, you should go see him.");
+ next;
+
+ mesn "Narrator";
+ mesc(l("Captain Nard is in the room to your right."), 9);
+ next;
+ restorecam;
+
+ close;
+
+L_Key:
+ warp "000-1", 93, 100;
+ close;
+
+L_GotoNard:
+ setcamnpc "Julia";
+ mesn "Julia";
+ mesq l("The captain is waiting for you! Hurry up.");
+ next;
+ restorecam;
+
+ close;
+
+L_End:
+ mesn "Narrator";
+ mesq col(l("This door is locked."), 9);
+ setcamnpc "Julia";
+ next;
+ mesn "Julia";
+ mesq l("We're soon leaving that island, please return to your cabine.");
+ next;
+ restorecam;
+
+ close;
+}
+
+000-2-0,33,28,0 script AreaNPC#doors2 NPC_HIDDEN,0,0,{
+
+OnTouch:
+ .@julia = getq(ShipQuests_Julia);
+ if (.@julia == 2) goto L_Warp;
+ close;
+
+L_Warp:
+ warp "000-2-3", 20, 27;
+ close;
+}
diff --git a/npc/000-2-0/julia.txt b/npc/000-2-0/julia.txt
new file mode 100644
index 00000000..4992f949
--- /dev/null
+++ b/npc/000-2-0/julia.txt
@@ -0,0 +1,289 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Qwerty Dragon
+// Vasily_Makarov
+// Description:
+// Allows to change language and talks about what happened to him.
+// 2 Bits Array:
+// ShipQuests
+// Variables:
+// 0 ShipQuests_Julia
+// 1 ShipQuests_ChefGado
+// 2 ShipQuests_Nard
+// Values:
+// Julia:
+// 10 Default, no quest given.
+// 01 Need to see Julia.
+// 02 Has been registered by Julia.
+// Gado:
+// 10 Default, no quest given.
+// 11 Quest accepted.
+// 12 Ingredients collected, ready to poison Julia.
+// 13 Julia poisoned.
+// 14 Quest complete. Chef Gago wins.
+// 15 Quest complete. Julia wins (poison dish returned).
+// 16 Quest complete. Julia wins.
+// Nard:
+// 20 Introduction of the boxes and Nard. This is displayed when the player never spoke to Nard or his box.
+// 21 Nard spoke and gave access to the outdoor of the ship.
+// 22 Completed the Gugli quest.
+// 23 ChefGado Quest accepted.
+// 24 ChefGado Quest completed and "Introduction" chapter finalized.
+// 25 Reward taken from the box.
+
+000-2-0,27,24,0 script Julia NPC_JULIA,2,10,{
+
+ function ynMenu {
+ if (select(l("Yes, I do."), l("No, none.")) == 1) {
+ return;
+ }
+ closeclientdialog;
+ }
+
+ function poisonJulia {
+ mes "";
+ mesn;
+ mesq l("Seems yummy! Let me taste it!");
+ next;
+ mesq l("Hmmm, hm... *cough*, *cough*, *burp*, *cough*. What... What is that?!... *cough*, *burp*... Damn Gado... *cough*");
+ if (countitem(PoisonedDish) > 0) delitem PoisonedDish, 1;
+ setq ShipQuests_ChefGado, 3;
+ close;
+ }
+
+ function gotoSleep {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You already did enough for us, follow Nard's advice and get some rest."),
+ l("We are at half a day from our final destination, by the time that you wake up I'm sure that we will be there!"),
+ l("Do you have any other questions for me?");
+ ynMenu;
+ return;
+ }
+
+ function heardRumors {
+ mes "";
+ mesn;
+ mesq l("You shouldn't believe every tale drunken sailors tell you.");
+ next;
+
+ select
+ l("Let's say the person who told me about that is well respected on this ship and never drunk.");
+
+ mes "";
+ mesn;
+ mesq l("Hahaha! All sailors aboard this ship are always drunk... Well... Except... Wait, what?! Nard told you?!");
+ next;
+ mesq l("Doesn't he like the way I'm taking care of his ship? Everything is clean and tidy with me, rightful lieutenant of La Johanne.");
+ next;
+ mesq l("I give tasks to every single sailor, all day long. That should make him happy!");
+ next;
+
+ select
+ l("Well... I don't think it is the best way to rule a ship. Think about it."),
+ l("In fact, everything seems to work perfectly under your guidance. Nard has made the right choice.");
+
+ if (@menu == 1)
+ {
+ closeclientdialog;
+ end;
+ }
+
+ mes "";
+ mesn;
+ mesq l("I'm glad you're on my side.");
+ next;
+ mesq l("Take this money as a reward for your nice words.");
+
+ setq ShipQuests_ChefGado, 6;
+ Zeny += 100;
+ message strcharinfo(0), l("You receive @@ E!", 100);
+ getexp 8, 0;
+ close;
+ }
+
+ function gotRegrets {
+ mes "";
+ mesn;
+ mesq l("Why? And who should you bring it back to?");
+ next;
+
+ select
+ l("Ehm... He was really upset because of some past stories.");
+
+ mes "";
+ mesn;
+ mesq l("Gado! That coward lives in the past, I will ask Nard to punish him, again!");
+ next;
+ mesq l("Take this money for your wise choice. But do not try it again. The open sea has been merciful with you once... Do not further tempt the fates!");
+
+ setq ShipQuests_ChefGado, 5;
+ Zeny += 200;
+ message strcharinfo(0), l("You receive @@ E!", 200);
+ getexp 15, 0;
+ close;
+ }
+
+ function basicSkill {
+ mes "";
+ mesn;
+ mesq l("Let me check into it...");
+ next;
+ adddefaultskills;
+ mesq l("Here you go, everything is fixed.");
+ emotion E_HAPPY;
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+ ynMenu;
+ return;
+ }
+
+ function chooseLang {
+ mes "";
+ mesn;
+ mesq l("Of course! Tell me which language you speak and I will change the note on the ship passenger list.");
+ next;
+
+ asklanguage(LANG_IN_SHIP);
+
+ mes "";
+ mesn;
+ mesq l("Ok, done.");
+
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+ ynMenu;
+ return;
+ }
+
+ function whereAmI {
+ mes "";
+ mesn;
+ mesq l("You're on a ship, we're on our way to the commercial capital of Artis.");
+ next;
+ mesq l("We should be there in a few days, once we arrive, I will warn the Legion of Aemil about what happened, I'm sure they can help.");
+ next;
+ mesq l("But for now, you can relax on the ship, or visit the island we're docked at! Its a small island, but a good place to get some exercise and stretch your legs.");
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+ ynMenu;
+ return;
+ }
+
+ function whatHappened {
+ mes "";
+ mesn;
+ mesq l("We thought that you could help us understand this, all we know is that we found you cast in the sea, adrift on your raft.");
+ next;
+ mesq l("You were in bad shape, you should be happy we found you before the sea killed you.");
+ next;
+ mesq l("Oh, and there was this inscription on your raft. It represents the Legion of Aemil, one of the four main guilds of Gasaron. Does that help you remember anything, anything at all?");
+ next;
+
+ select
+ l("Sorry, but I can't tell you anything about that."),
+ l("Nothing, sorry.");
+
+ mes "";
+ mesn;
+ mesq l("No problem, do you have any other questions for me?");
+ next;
+ ynMenu;
+ return;
+ }
+
+ function readRules {
+ mes "";
+ mesn;
+ mesq l("Of course, they are on the left wall, go have a look at them.");
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+ ynMenu;
+ return;
+ }
+
+ function mainMenu {
+ do
+ {
+ .@q2 = getq(ShipQuests_ChefGado);
+ .@q3 = getq(ShipQuests_Nard);
+ .@q4 = getq(General_Narrator);
+
+ selectd
+ rif(.@q3 == 5 && .@q4 < 1, l("What can I do now?")),
+ rif(.@q3 == 3 && .@q2 == 0, l("I heard rumors about some old hostilities between you and Gado. Are they true?")),
+ rif(.@q2 == 2 && countitem(PoisonedDish), l("Well... No wait, I have something for you but you shouldn't eat it... I'm taking it back to the kitchen.")),
+ rif(.@q2 == 2 && countitem(PoisonedDish), l("I have brought you a tasty present for your delicate mouth.")),
+ rif(getskilllv(NV_BASIC) < 6, l("Something is wrong with me, I can't smile nor sit.")),
+ l("I made a mistake, I would like to change my language."),
+ l("Could you explain to me where I am?"),
+ l("What happened to me?"),
+ l("Can I read these rules again?"),
+ l("Nothing, sorry.");
+
+ switch (@menu)
+ {
+ case 1: gotoSleep; break;
+ case 2: heardRumors; break;
+ case 3: gotRegrets; break;
+ case 4: poisonJulia; break;
+ case 5: basicSkill; break;
+ case 6: chooseLang .@s$; break;
+ case 7: whereAmI; break;
+ case 8: whatHappened; break;
+ case 9: readRules; break;
+ case 10: closeclientdialog; end;
+ }
+ } while (1);
+ }
+
+ mesn;
+ mesq l("Hello dear!");
+ next;
+ mesq l("What do you want today?");
+ next;
+
+ mainMenu;
+
+OnTouch:
+ .@q = getq(ShipQuests_Julia);
+ if (.@q > 1) end;
+
+ checkclientversion;
+
+ mesn;
+ mesq l("Hi, nice to see you!");
+ next;
+ mesq l("My name is Julia, it is me who took care of you after we found you in the sea.");
+ next;
+ mesq l("I'm glad to see you're okay.");
+ next;
+
+ mesq l("I'm sure that you've got some questions for me, feel free to ask them, but first I need to tell you the rules of proper social conduct on board.");
+
+ narrator S_LAST_NEXT,
+ l("There is a paper with some rules written on it.");
+
+ GameRules 8 | 4;
+
+ mesn;
+ mesq l("Oh, and I almost forgot! Do not give the password of your room to anybody! I am the only one who has the other key and I won't ask for yours so keep it secret and try not to use the same password for any other room in the future.");
+ next;
+ mesq l("If you want to read this page again, there is a copy up on the left wall.");
+ next;
+ mesq l("You can also read The Book of Laws at any time to see the rules.");
+ setq ShipQuests_Julia, 2;
+ next;
+ mesq l("I think I'm done with that now. Do you have any questions?");
+ next;
+ mainMenu;
+ end;
+
+OnInit:
+ .distance = 10;
+ .quest_debug = ShipQuests_Julia;
+}
diff --git a/npc/000-2-0/mapflags.txt b/npc/000-2-0/mapflags.txt
new file mode 100644
index 00000000..d3a4bd22
--- /dev/null
+++ b/npc/000-2-0/mapflags.txt
@@ -0,0 +1 @@
+000-2-0 mapflag town
diff --git a/npc/000-2-0/note.txt b/npc/000-2-0/note.txt
new file mode 100644
index 00000000..fcb28f71
--- /dev/null
+++ b/npc/000-2-0/note.txt
@@ -0,0 +1,27 @@
+// Evol scripts.
+// Authors:
+// gumi
+// Qwerty Dragon
+// Reid
+// WildX
+// Description:
+// A small note presenting the 6 main rules of Evol Online.
+
+000-2-0,29,25,0 script Note NPC_PAPER_NOTE,{
+ narrator S_LAST_NEXT,
+ l("There is a paper with some rules written on it.");
+
+ GameRules 8 | 4;
+
+ narrator S_NO_NPC_NAME,
+ l("Following these lines are some other writings on this paper."),
+ l("Do not give the password of your room to anybody! Keep it secret and try not to use the same one in any other room in the future. - Julia"),
+ l("Does anyone know a good place to hang out in Esperia? - M. Arpan"),
+ l("Other things are written but are not legible anymore.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/_import.txt b/npc/000-2-1/_import.txt
new file mode 100644
index 00000000..ba87b23e
--- /dev/null
+++ b/npc/000-2-1/_import.txt
@@ -0,0 +1,17 @@
+// Map 000-2-1: Second Deck
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-2-1/_mobs.txt",
+"npc/000-2-1/_savepoints.txt",
+"npc/000-2-1/_warps.txt",
+"npc/000-2-1/alige.txt",
+"npc/000-2-1/arpan.txt",
+"npc/000-2-1/chefgado.txt",
+"npc/000-2-1/chest.txt",
+"npc/000-2-1/dan.txt",
+"npc/000-2-1/devis.txt",
+"npc/000-2-1/hammock.txt",
+"npc/000-2-1/knife.txt",
+"npc/000-2-1/mapflags.txt",
+"npc/000-2-1/peter.txt",
+"npc/000-2-1/q'onan.txt",
+"npc/000-2-1/story_save.txt",
diff --git a/npc/000-2-1/_mobs.txt b/npc/000-2-1/_mobs.txt
new file mode 100644
index 00000000..e4b38bfc
--- /dev/null
+++ b/npc/000-2-1/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-1: Second Deck mobs
+000-2-1,52,32,21,9 monster Piou 1002,3,30000,20000
diff --git a/npc/000-2-1/_savepoints.txt b/npc/000-2-1/_savepoints.txt
new file mode 100644
index 00000000..da074f25
--- /dev/null
+++ b/npc/000-2-1/_savepoints.txt
@@ -0,0 +1,54 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-1: Second Deck saves
+000-2-1,40,37,0 script #save_000-2-1_40_37 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+000-2-1,46,37,0 script #save_000-2-1_46_37 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+000-2-1,50,38,0 script #save_000-2-1_50_38 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+000-2-1,55,40,0 script #save_000-2-1_55_40 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/000-2-1/_warps.txt b/npc/000-2-1/_warps.txt
new file mode 100644
index 00000000..db3a1c8e
--- /dev/null
+++ b/npc/000-2-1/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-1: Second Deck warps
+000-2-1,72,30,0 warp #000-2-1_72_30 0,0,000-2-0,31,26
diff --git a/npc/000-2-1/alige.txt b/npc/000-2-1/alige.txt
new file mode 100644
index 00000000..919b712d
--- /dev/null
+++ b/npc/000-2-1/alige.txt
@@ -0,0 +1,321 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Alige
+// Qwerty Dragon
+// Reid
+// Vasily_Makarov
+// Description:
+// Hidden in a ship's hole.
+// 2 bits array:
+// ShipQuests
+// Variable:
+// ShipQuests_Alige
+// Values:
+// 0 Never talk.
+// 1 First talk.
+// 2 Accept the task.
+// 3 Bring first food.
+
+000-2-1,43,32,0 script AligeTrigger NPC_HIDDEN,1,1,{
+
+OnTouch:
+ if (getareausers() <= 1)
+ {
+ setnpcdir "Alige", 2;
+ stopnpctimer;
+ initnpctimer;
+ }
+
+ if (getq(ShipQuests_Alige) > 0) close;
+ doevent "Alige::OnFirstEncounter";
+
+ close;
+
+OnUnTouch:
+ if (getareausers() == 0)
+ {
+ setnpcdir "Alige", 4;
+ stopnpctimer;
+ initnpctimer;
+ }
+ close;
+
+OnTimer190:
+ stopnpctimer;
+
+ if (getnpcdir("Alige") == 2) setnpcdir "Alige", 6;
+ if (getnpcdir("Alige") == 4) setnpcdir "Alige", 8;
+
+ end;
+}
+
+000-2-1,43,31,0 script Alige NPC_ALIGE,{
+ .@q = getq(ShipQuests_Alige);
+ if (.@q > 1) goto L_AskForFood;
+
+ goto OnFirstEncounter;
+
+OnFirstEncounter:
+ setq ShipQuests_Alige, 1;
+
+ setcamnpc;
+ mesn "Hidden Person";
+ mesq l("Hey, psst! You're not a sailor, right?");
+ next;
+ restorecam;
+
+ menu
+ l("I am, who are you?"), -,
+ l("Indeed, I am not."), L_NeedHelp;
+
+ mes "";
+ mesn "Narrator";
+ mesc(l("The stowaway doesn't answer."), 9);
+
+ close;
+
+L_NeedHelp:
+ setcamnpc;
+ mes "";
+ mesn "Hidden Person";
+ mesq l("Good, good... Hey, could you help me please? I beg you, please, pleeeease...");
+ next;
+ restorecam;
+
+ menu
+ l("Why not, but who are you, and what kind of help do you need?"), L_CanHelp;
+ l("Sorry but I have no time for this."), -;
+
+ closeclientdialog;
+ close;
+
+L_CanHelp:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("My name is Alige, I've been hiding here for weeks. All I have to eat are these berries... berries... berries...");
+ next;
+ mesq l("I'm losing my mind here, I need something else to eat!");
+ next;
+ mesq l("Could you please bring me something which isn't a berry, and I'm not big on vegetables either. I need proteins!");
+ next;
+ restorecam;
+
+ menu
+ l("Sure, but what will you give me in exchange?"), L_AboutReward,
+ l("Why don't you come out?"), -;
+
+L_ExplainHiding:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("No, I can't. I won't! All I wanted was to travel across the seas for fun, growl... sniff. And in this hole in the floor, as you can see, I have lots of fun.");
+ next;
+ mesq l("Oh... um... actually... all I wanted was to get to Artis. Err... but I didn't, uhm... have enough money to pay for the ferry!");
+ next;
+ mesq l("Please don't tell people you saw me. I don't want to be decapitated or get thrown into the sea as food for sharks, or get my hair mussed!");
+ next;
+ restorecam;
+
+ if (getq(ShipQuests_Alige) == 2) goto L_SoAskForFood;
+ goto L_Accept;
+
+L_AboutReward:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("I'll share my berries with you if you help me.");
+ next;
+ restorecam;
+
+L_Accept:
+ menu
+ l("Understood, I will help you."), L_FirstAccepted,
+ l("What is Artis?"), L_Artis,
+ l("I think I should report you to the crew members."), -;
+
+ setcamnpc;
+ mesq l("Growl, sniff, grr! You'd better not tell anyone you saw me!");
+
+ close;
+
+L_Artis:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("It's a commercial port of Andorra, it's weird that you don't know about it since it is one of the most famous cities throughout the whole world. But hey, back to me. Remember me telling you that I'm hun...grrr...eee!");
+ next;
+ restorecam;
+
+ if (.@q == 2) goto L_SoAskForFood;
+ goto L_Accept;
+
+L_FirstAccepted:
+ if (getq(ShipQuests_Alige) >= 2) goto L_Accepted;
+ setq ShipQuests_Alige, 2;
+
+ goto L_Accepted;
+
+L_Accepted:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Great, what food do you have for me today?");
+ next;
+ restorecam;
+
+L_GiveFood:
+ mes "";
+
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+ .@id = requestitem();
+ if (.@id <= 0) goto L_Quit; // Quit message.
+ if (countitem(.@id) == 0) goto L_Quit; // If don't have the food
+
+ if (array_find(.vegetables, .@id) >= 0) goto L_NoReward; // In case of wrong food.
+ if (array_find(.poisonable, .@id) >= 0) goto L_Poison; // In case of poisoned food (or food with effects).
+ if (.@id == Piberries) goto L_NoMore; // In case of Piberries.
+ if (.@id == RedPlushWine) goto L_Drunk; // In case of Alcohol.
+
+ // Default message for non food
+ if (array_find(.commonfood, .@id) == -1) goto L_NoFood;
+
+ inventoryplace Piberries, 3;
+ delitem .@id, 1;
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Thank you so much! Here, have some of my berries.");
+
+ setq ShipQuests_Alige, 3;
+ getitem Piberries, rand(1, 3);
+ next;
+
+ goto L_ReturnMenu;
+
+L_NoReward:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("You don't expect me to eat that, do you? Give me something else!");
+ next;
+ restorecam;
+
+ goto L_GiveFood;
+
+L_Drunk:
+ setcamnpc;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I asked for food but... *hips* Ah, that'll do!");
+ restorecam;
+
+ goto L_GiveFood;
+
+L_NoFood:
+ setcamnpc;
+ // We must first determine if it is at least edible (IT_HEALING)
+ if (getiteminfo(.@id, ITEMINFO_TYPE) == IT_HEALING)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That looks too exotic for me to eat!");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That doesn't looks edible to me!");
+ }
+ restorecam;
+
+ goto L_GiveFood;
+
+L_ReturnMenu:
+ setcamnpc;
+ mesq l("Do you have anything else for me?");
+ next;
+ restorecam;
+
+ goto L_GiveFood;
+
+L_NoMore:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Grr, don't give me more berries! I don't want them, stupid berries, stupid... Stupid... Stupid!");
+ next;
+
+ goto L_ReturnMenu;
+
+L_Poison:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Don't try to poison me! I know what that does!");
+ next;
+ restorecam;
+ goto L_ReturnMenu;
+
+L_SoAskForFood:
+ setcamnpc;
+ mesn;
+ mesq l("So, do you have anything for me today?");
+ next;
+ restorecam;
+ goto L_IntroMenu;
+
+L_AskForFood:
+ setcamnpc;
+ mesn;
+ mesq l("Do you have anything for me today?");
+ next;
+ restorecam;
+
+L_IntroMenu:
+ menu
+ l("Yes."), L_GiveFood,
+ l("Where can I find some food?"), L_FindFood,
+ l("Why are you hiding?") + " " + l("Why don't you come out?"), L_ExplainHiding,
+ l("What is Artis?"), L_Artis,
+ l("I think I should report you to the crew members."), -;
+
+ setcamnpc;
+ mesq l("Growl, sniff, grr! You'd better not tell anyone you saw me!");
+
+ close;
+
+L_FindFood:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("There are some flying yellow plushes around you. They're called pious. Getting a roasted leg of one of them would be perfect.");
+ next;
+ mesq l("I'd like to catch one of them, but they fly away when I try.");
+ next;
+ mesq l("Walking around a bit, it'll be easy for you to catch one, I bet. Impale one of them for me please.");
+ next;
+ restorecam;
+ mesn "Narrator";
+ mesc(l("You can attack a monster by clicking on it, or from your keyboard you can press the 'A' key to select the monster followed by 'Ctrl' to attack it."), 9);
+ next;
+ mesc(l("Once the monster is dead, click on the dropped items to add them to your inventory. You can also use the 'Z' key to claim the drops."), 9);
+
+ close;
+
+L_Quit:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Too bad... Come back when you'll have some nice food for me. Growl... grumble... grumble.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+
+ // Array of foods (remember to update in 001-2-22 as well)
+ setarray .commonfood, Bread, Fungus, Cheese, PiouLegs, Aquada, HalfCroconut, Plushroom, PumpkinJuice, Manana, Curshroom, Carrot, CarpSandwich, PioulegSandwich;
+ setarray .vegetables, Acorn, LettuceLeaf, Croconut, MananaSandwich;
+ setarray .poisonable, SeaDrops, PinkBlobime, PumpkinSeeds, UrchinMeat, EasterEgg;
+ end;
+}
diff --git a/npc/000-2-1/arpan.txt b/npc/000-2-1/arpan.txt
new file mode 100644
index 00000000..106d9aaa
--- /dev/null
+++ b/npc/000-2-1/arpan.txt
@@ -0,0 +1,304 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Qwerty Dragon
+// Description:
+// Explains to the player how he got here.
+// Variable:
+// 0 ShipQuests_Arpan
+// 1 ShipQuests_Julia
+// 2 ShipQuests_ArpanMoney
+// Values:
+// 00 Has not talked to Arpan yet.
+// 01 Talked to Arpan and needs to get the clothes.
+// 02 Has the clothes.
+// 03 Has and equipped the clothes.
+// 10 Has not talked to Julia
+// 11 Need to see Julia
+// 12 Has been registered by Julia
+// 20 Does not knows about money
+// 21 Has not taken possession from Arpan
+// 22 Took money from Arpan
+// 23 Took money and clothes (Legacy only)
+
+000-2-1,49,36,0 script LeftDoorCheck NPC_HIDDEN,0,0,{
+ .@q = getq(ShipQuests_Arpan);
+ if (.@q == 0) doevent "Magic Arpan::OnTalk";
+
+ close;
+}
+
+000-2-1,54,36,0 script RightDoorCheck NPC_HIDDEN,0,0,{
+ .@q = getq(ShipQuests_Arpan);
+ if (.@q == 0) doevent "Magic Arpan::OnTalk";
+
+ close;
+}
+
+000-2-1,47,32,0 script LeftBarrierCheck NPC_HIDDEN,0,2,{
+ .@q = getq(ShipQuests_Arpan);
+ if (.@q > 2) close;
+ if (.@q == 2 && getequipid(equip_torso) == 1300 && getequipid(equip_legs) == 2200) goto L_EquipDone;
+ if (.@q == 2) goto L_Equip;
+ if (.@q == 1) goto L_GetCloth;
+
+ doevent "Magic Arpan::OnClothNotTaken";
+
+L_Equip:
+ slide 49, 32;
+ doevent "Magic Arpan::OnEquip";
+
+ close;
+
+L_GetCloth:
+ slide 49, 32;
+ doevent "Magic Arpan::OnClothNotTaken";
+
+ close;
+
+L_EquipDone:
+ setq ShipQuests_Arpan, 3;
+
+ close;
+}
+
+000-2-1,56,32,0 script RightBarrierCheck NPC_HIDDEN,0,2,{
+ .@q = getq(ShipQuests_Arpan);
+ if (.@q > 2) close;
+ if (.@q == 2 && getequipid(equip_torso) == 1300 && getequipid(equip_legs) == 2200) goto L_EquipDone;
+ if (.@q == 2) goto L_Equip;
+ if (.@q == 1) goto L_GetCloth;
+
+ doevent "Magic Arpan::OnClothNotTaken";
+
+L_Equip:
+ slide 55, 32;
+ doevent "Magic Arpan::OnEquip";
+
+ close;
+
+L_GetCloth:
+ slide 55, 32;
+ doevent "Magic Arpan::OnClothNotTaken";
+
+ close;
+
+L_EquipDone:
+ setq ShipQuests_Arpan, 3;
+
+ close;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+000-2-1,49,33,0 script Magic Arpan NPC_MAGIC_ARPAN,{
+ .@q = getq(ShipQuests_Arpan);
+ .@q_nard = getq(ShipQuests_Nard);
+ .@q_julia = getq(ShipQuests_Julia);
+ if (.@q == 2 && getequipid(equip_torso) == 1300 && getequipid(equip_legs) == 2200) goto L_EquipDone;
+
+OnTalk:
+ mesn;
+
+ if (.@q > 0) goto L_Menu;
+ setq ShipQuests_Arpan, 1;
+ deltimer("Magic Arpan::OnSlow");
+
+ mesq l("Yeye, you are really lucky to be alive. You are in good enough shape for walking, do you remember what happened?");
+ next;
+
+ menu
+ l("I only remember I was rescued by you."), L_Story,
+ l("I can't remember anything."), L_OhWell;
+
+OnClothNotTaken:
+ mesn;
+ mesq l("Yeye, you still did not get your new clothes from the chest next to your bed!");
+
+ close;
+
+OnEquip:
+ mesn "Narrator";
+ mesc(l("To open your inventory, use the F3 key or use your mouse to select it in the above menu in your client."), 9);
+ next;
+ mesc(l("When your inventory is open, you can equip an item by selecting it and clicking 'Equip'. You can do the same to remove an item by clicking on 'Unequip'."), 9);
+ next;
+ mesc(l("Items have different effects. Some will heal you, some can be used as weapons or armor, and some can be sold for gold."), 9);
+
+ close;
+
+L_OhWell:
+ mes "";
+ mesq l("Oh well, we rescued you when you were yaying adrift in the sea.");
+ next;
+
+ select
+ l("And then what happened?");
+
+L_Story:
+ mes "";
+ mesq l("You were yaying sleeping for quite some time there. Our shipkeeper, Julia, was here with you, and she did her best to heal your injuries.");
+ next;
+ if (.@q_julia == 0) setq ShipQuests_Julia, 1;
+ mesq l("Yaya, you should go see her! She'll be happy to see you.");
+ next;
+ mesq l("Also, we took your yayed clothes, as they were... Yeyeye... In a bad shape. Go check the chest near your bed, there are some other ones inside.");
+ setcamnpc "Chest";
+
+ close;
+
+L_Menu:
+ mesq l("What yeye could I do for you today?");
+ next;
+ .@equipped = getequipid(equip_torso) == 1300 && getequipid(equip_legs) == 2200;
+
+ menu
+ rif(.@q_nard == 5 && getq(General_Narrator) < 1, l("What can I do now?")), L_GotoSleep,
+ l("Could you tell me where I am?"), L_Where,
+ l("Where can I find Julia?"), L_Julia,
+ l("Who are you?"), L_Who,
+ rif(getq(ShipQuests_ArpanMoney) == 1, l("Do you know what happened to the gold I had when you guys saved me?")), L_WhereMoney,
+ rif(getq(ShipQuests_ArpanMoney) < 2, l("Where are my old clothes?")), L_WhereOldClothes,
+ rif(getq(ShipQuests_ArpanMoney) == 2 && islegacyaccount(), l("About my my old clothes...")), L_LegacyClothes,
+ rif(!.@equipped, l("What should I do after taking these clothes?")), L_WhatCloth,
+ rif(!.@equipped, l("Thank you, I'll take them and put them on.")), -,
+ l("Nothing, sorry."), -;
+
+ closeclientdialog;
+ close;
+
+L_Where:
+ mes "";
+ mesn;
+ mesq l("You're on our ship, we made port to a little island and we're actually yeyending our long merchant traveling adventure at the city of Artis.");
+ next;
+ mesq l("We will be yaying there in a few days, so we will drop you off there.");
+ next;
+ mesq l("You will see, citizens are polite and you can still ask for help in the Legion of Aemil. They can help find a job for you or maybe help you find out what happened to you out at sea!");
+ next;
+
+ goto L_Menu;
+
+L_Julia:
+ mes "";
+ mesn;
+ mesq l("She's on the upper level, yeye can't miss her. She's the only girl in this crew so far.");
+ next;
+
+ mesn "Narrator";
+ mesc(l("Julia is on the upper level of the ship, use the arrow keys to walk to the stairs or click on the stairs at the top right of your screen."), 9);
+ next;
+
+ goto L_Menu;
+
+L_Who:
+ mes "";
+ mesn;
+ mesq l("Sorry! I forgot to introduce myself. My name is Arpan, but other sailors call me Magic Arpan because I know one or two yaing magic spells.");
+ next;
+
+ goto L_Menu;
+
+L_WhereOldClothes:
+ mes "";
+ mesn;
+ mesq l("We tried to clean them but the sea water mostly destroyed them. It's why we gave you these clothes. They're not very nice, but that's all that we have for you.");
+ next;
+ mes l("Oh, now that I remember, we also found some money in your pockets, here it is!");
+ next;
+
+ setq ShipQuests_ArpanMoney, 2;
+ .@q = getq(ShipQuests_Arpan);
+ Zeny += 10;
+ message strcharinfo(0), l("You receive @@ E!", 10);
+
+ if (islegacyaccount())
+ goto L_LegacyClothes;
+
+ goto L_BeforeMenu;
+
+L_LegacyClothes:
+ if (islegacyaccount()) {
+ mesn strcharinfo(0);
+ select
+ l("But... I remember that my clothes were very dear to me..."),
+ l("Oh okay.");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("Well, you can have them back, but they're yayaya, mostly destroyed. Not sure what yeye are going to do with that.");
+ getitem ClothesPack, 1;
+ setq ShipQuests_ArpanMoney, 3;
+ }
+ }
+ goto L_BeforeMenu;
+
+L_WhereMoney:
+ mes "";
+ mesn;
+ mesq l("Oh right, I totally forgot about that, here you go.");
+ next;
+
+ setq ShipQuests_ArpanMoney, 2;
+ .@q = getq(ShipQuests_Arpan);
+ Zeny += 10;
+ message strcharinfo(0), l("You receive @@ E!", 10);
+
+ goto L_BeforeMenu;
+
+L_WhatCloth:
+ mes "";
+ mesn;
+ mesq l("Oh yeyeye... As they are not edible, you can maybe try to equip them?");
+ next;
+
+ mesn "Narrator";
+ mesc(l("To open your inventory, use the F3 key or use your mouse to select it in the above menu in your client."), 9);
+ next;
+ mesc(l("When your inventory is open, you can equip an item by selecting it and clicking 'Equip'. You can do the same to unequip an item by clicking on 'Unequip'."), 9);
+ next;
+ mesc(l("Items have different effects. Some will heal you, some can be used as weapons or armor, and some can be sold for gold."), 9);
+ next;
+
+L_BeforeMenu:
+ mesn;
+ goto L_Menu;
+
+L_EquipDone:
+ setq ShipQuests_Arpan, 3;
+ goto L_Menu;
+
+L_GotoSleep:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You already did enough for us, do you want to follow Nard's advice and get some rest?");
+
+ switch (select(l("Yes."), l("No.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Fine."),
+ l("We are at half a day from our final destination, by the time that you wake up I'm sure that we will be there!");
+
+ closeclientdialog;
+ doevent "#name3::OnClick";
+ close;
+
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Alright, take your time we are not in a hurry.");
+
+ break;
+ }
+
+ goto L_Menu;
+
+OnSlow:
+ dispbottom(l("Use arrow keys to walk around and leave this room."));
+ npctalk3(l("Please come talk to me, I'll help you get dressed."));
+ addtimer(90000,"Magic Arpan::OnSlow");
+ close;
+
+OnInit:
+ .distance = 5;
+ end;
+}
diff --git a/npc/000-2-1/chefgado.txt b/npc/000-2-1/chefgado.txt
new file mode 100644
index 00000000..0e3a71be
--- /dev/null
+++ b/npc/000-2-1/chefgado.txt
@@ -0,0 +1,226 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Description:
+// La Johanne Chef.
+// Variable:
+// ShipQuests_ChefGado
+// ShipQuests_Nard
+// Values:
+// 0 Default, no quest given.
+// 1 Quest accepted.
+// 2 Ingredients collected, ready to poison Julia.
+// 3 Julia poisoned.
+// 4 Quest complete. Chef Gago wins.
+// 5 Quest complete. Julia wins (poison dish returned).
+// 6 Quest complete. Julia wins.
+
+000-2-1,27,28,0 script Chef Gado NPC_CHEF_GADO,{
+ .@q = getq(ShipQuests_ChefGado);
+ .@n = getq(ShipQuests_Nard);
+ if (.@q == 1) goto L_QuestAccepted;
+ if (.@q == 2) goto L_PoisonAccepted;
+ if (.@q == 3) goto L_PoisonJulia;
+ if (.@q == 4) goto L_QuestComplete;
+ if (.@q == 5 && countitem(PoisonedDish) > 0) goto L_Aborting;
+ if (.@q > 4) goto L_QuestAborted;
+ if (.@n == 3) goto L_QuestStart;
+
+ mesn;
+ .@r = rand(3);
+ if (.@r == 0) mesq l("What are you doing in my kitchen?! Get out, it's not a place for kids!");
+ if (.@r == 1) mesq l("Where is the damn salt?! Give me the salt, I know you have it!");
+ if (.@r == 2) mesq l("Are you going to stand here all day long? Do the dishes or go away.");
+
+ if (getq(General_SmearedHands) < 3) {
+ next;
+ select
+ l("I'll get moving, sorry!"),
+ //rif(.@r == 1 && countitem(Salt), l("Offer him the salt")),
+ l("Can you teach me cooking?");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("NO! I am busy, can't you see?!");
+ next;
+ mesn;
+ mesq l("When we reach Artis, maybe, but not now!");
+ }
+ }
+ close;
+
+L_QuestStart:
+ mesn;
+ mesq l("So it seems I have another stomach to fill. Those bastards have no respect for who feeds them every damn day!");
+ next;
+
+ menu
+ l("How rude! What is the reason behind your malice?"), L_Rude,
+ l("I swear, I do not eat so much."), -;
+
+ mes "";
+ mesn;
+ mesq l("Yeah, yeah, of course you don't...");
+
+ close;
+
+L_Rude:
+ mes "";
+ mesn;
+ mesq l("UAHAHAHAAH! I am the cook of that bunch of donkeys, and I can be rude with everyone from this bossy captain to that harpy-lady!");
+ next;
+
+ select
+ l("Harpy-lady?");
+
+ mes "";
+ mesn;
+ mesq l("I am sure you know her. Nice dress, large smile and a constant flux of orders and rules. Julia they call her!");
+ next;
+ mesq l("You have to know that there was a time during which I was the unopposed lieutenant of this crew. Then one day one of those damn sailors brought that 'nice' lady here.");
+ next;
+ mesq l("I will not tell you all the details, but after a month, she was ruling the ship and I was sent down here, cooking for those traitors!");
+ next;
+ mesq l("But I swear that one day... Oh... My tasty revenge! Hhm, actually I wonder if... Maybe...");
+ next;
+
+ select
+ l("M... Maybe?");
+
+ mes "";
+ mesn;
+ mesq l("Well, eh-heh... Welcome aboard, young fellow!");
+ next;
+ mesq l("I just realized I am lacking some common things, and one key ingredient, to prepare a... A special recipe.");
+ next;
+ mesq l("I only need 2 @@, 2 @@s, 1 @@...", getitemlink(PiouLegs), getitemlink(HalfCroconut), getitemlink(Aquada));
+ next;
+ mesq l("... and 1 @@.", getitemlink(SeaDrops));
+ next;
+
+ menu
+ l("Sea water?! I will not help you with your evil plan!"), L_Quit,
+ l("Sure, why not?"), -;
+
+ setq ShipQuests_ChefGado, 1;
+ mes "";
+ mesn;
+ mesq l("Well done! Collect all the ingredients and then come back here. You will be rewarded once I am satisfied that they understand who rules this ship!");
+ next;
+ mesq l("Before you go, let me tell you how to get @@s, because you don't look very smart.", getitemlink(HalfCroconut));
+
+ goto L_OpenCroconut;
+
+L_QuestAccepted:
+ mesn;
+ mesq l("Have you collected all the ingredients for my recipe? The special one too?");
+ next;
+
+ menu
+ rif(countitem(PiouLegs) > 1 && countitem(HalfCroconut) > 1 && countitem(Aquada) > 0 && countitem(SeaDrops) > 0, l("All your... Fresh ingredients are ready to be cooked.")), L_GotAll,
+ l("What are your needs?"), L_Need,
+ l("Where can I find a half croconut?"), L_OpenCroconut,
+ l("Not yet. I will be back soon."), L_Quit;
+
+L_OpenCroconut:
+ mes "";
+ mesn;
+ mesq l("Take a @@ and try opening it using something like a sharp knife. I doubt you'll succeed, you're being so weak in everything.", getitemlink(Croconut));
+ next;
+ mesq l("Now move!");
+
+ close;
+
+L_GotAll:
+ mes "";
+
+ inventoryplace PoisonedDish, 1;
+
+ delitem PiouLegs, 2;
+ delitem HalfCroconut, 1;
+ delitem Aquada, 1;
+ delitem SeaDrops, 1;
+
+ mesn;
+ mesq l("Let me see... Crispy legs, disgusting liquids... Let's start!");
+ next;
+ mesq l("Water, salt, spicy herbs and meat stuffed with my special surprise!");
+ next;
+ mesq l("Done. Here, take it! Now, here is the plan. Go talk to her and offer our beautiful lady a bite of her arrogance!");
+
+ setq ShipQuests_ChefGado, 2;
+ getitem PoisonedDish, 1;
+ close;
+
+L_Need:
+ mes "";
+ mesn;
+ mesq l("Shhht, don't say it that loud...");
+ next;
+ mesq l("I only need 2 @@, 2 @@s, 1 @@...", getitemlink(PiouLegs), getitemlink(HalfCroconut), getitemlink(Aquada));
+ next;
+ mesq l("... and 1 @@.", getitemlink(SeaDrops));
+
+ close;
+
+L_PoisonAccepted:
+ mesn;
+ mesq l("Fool! Just come back here when you'll be done with our little... 'Secret mission'.");
+
+ close;
+
+L_PoisonJulia:
+ mesn;
+ mesq l("The usurper has been punished! This is a great day! Take this reward as a prize for your loyalty to the old commander!");
+
+ setq ShipQuests_ChefGado, 4;
+ Zeny += 200;
+ message strcharinfo(0), l("You receive @@ E!", 200);
+ inventoryplace Bread, 1;
+ getitem Bread, 1;
+ getexp 15, 0;
+
+ close;
+
+L_QuestComplete:
+ mesn;
+ mesq l("Oh, it's you. I think it's better we do not talk for a while. They suspect something.");
+
+ close;
+
+L_Aborting:
+ mesn;
+ mesq l("Wait, why do you still have the dish with you?!");
+ next;
+
+ select
+ l("I informed Julia about your monstrous plan.");
+
+ mes "";
+ mesn;
+ mesq l("Are you mad?!");
+ next;
+ mesq l("Give me back this dish, you dirty liar!");
+
+ if (countitem(PoisonedDish) > 0) delitem PoisonedDish, 1;
+
+ next;
+ mesq l("You're like the rest of this filthy crew, I can't trust you!");
+
+ close;
+
+L_QuestAborted:
+ mesn;
+ mesq l("You're like the rest of this filthy crew. Your name is now on the traitors list!");
+
+ close;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/chest.txt b/npc/000-2-1/chest.txt
new file mode 100644
index 00000000..f9ec2742
--- /dev/null
+++ b/npc/000-2-1/chest.txt
@@ -0,0 +1,72 @@
+// Evol scripts.
+// Authors:
+// 4144
+// gumi
+// omatt
+// Reid
+// Description:
+// A box with clothes for new players.
+// Variable:
+// ShipQuests_Arpan
+// Values:
+// 1 Talked to Arpan and needs to get clothes.
+// 2 Has the clothes.
+
+000-2-1,51,37,0 script Chest#000-2-1 NPC_CHEST_BIG,2,4,{
+
+ .@questState = getq(ShipQuests_Arpan);
+
+ if (.@questState == 0)
+ {
+ npctalk3 l("You should talk to Magic Arpan first.");
+ end;
+ }
+
+ if (.busy == false)
+ {
+ if (.@questState <= 1)
+ {
+ inventoryplace CreasedShirt, 2;
+ setq ShipQuests_Arpan, 2;
+ getitem CreasedShirt, 1;
+ getitem CreasedShorts, 1;
+ npctalk3 l("You take the clothes from the chest.");
+ }
+
+ specialeffect(.dir == 0 ? 24 : 25, AREA, getnpcid()); // closed ? opening : closing
+ .dir = .dir == 0 ? 2 : 6; // closed ? opening : closing
+ .busy = true; // lock the animation
+ initnpctimer;
+ }
+ end;
+
+OnTimer220:
+ .dir = .dir == 6 ? 0 : 4; // closing ? closed : open
+ end;
+
+OnTimer500:
+ .busy = false; // unlock
+
+ if (.dir == 0)
+ {
+ stopnpctimer; // stop here if the chest is closed
+ }
+ end;
+
+OnUnTouch:
+ if (getareausers(.x - 2, .y - 4, .x + 2, .y + 6) > 0 || .dir == 0)
+ {
+ end;
+ }
+OnTimer30000:
+ .busy = true;
+ .dir = 6; // closing
+ specialeffect(25, AREA, getnpcid()); // closing
+ setnpctimer 0;
+OnTouch:
+ end;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/dan.txt b/npc/000-2-1/dan.txt
new file mode 100644
index 00000000..f336402d
--- /dev/null
+++ b/npc/000-2-1/dan.txt
@@ -0,0 +1,93 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// There are two kinds of dialogues in this script.
+// Dan will randomly choose between a useless sentence, and a quest in Artis.
+
+000-2-1,32,31,0 script Dan#000-2-1 NPC_DEMON_MAN,{
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ close;
+ }
+
+ mesn;
+ .@q = rand(3);
+ if (.@q == 0) goto L_QuestStory;
+
+ mesq l("You see these pious around us?");
+ next;
+ mesq l("It seems that we are close to an island, we should take a look at the upper level.");
+
+ close;
+
+L_QuestStory:
+ mesq l("It's so hard to find the motivation...");
+ next;
+
+ menu
+ l("Why?"), -,
+ l("I guess so... I will leave you alone."), L_Quit;
+
+ mes "";
+ mesn;
+ mesq l("Oh, it's you.");
+ next;
+ mesq l("So, you finally woke up? We all thought you were in something like... You know, one of these long comas.");
+ next;
+
+ menu
+ l("I'm still in a coma, but my ghost is haunting you!"), L_Quit,
+ l("It was something like a long nap."), -;
+
+ mes "";
+ mesn;
+ mesq l("It's good, good... I have a friend who is still in a coma, but I can't be with her without working...");
+ next;
+ mesq l("The fear to see her sleeping on this quiet and lonely bed is becoming more and more unbearable, I think that I won't get the bravery to see her this time...");
+ next;
+
+ menu
+ l("Who is she?"), L_She,
+ l("Do you want me to go see her instead of you?"), L_Quest,
+ l("I don't know what to say..."), -;
+
+ mes "";
+ mesn;
+ mesq l("There's nothing to say, don't worry.");
+
+ close;
+
+L_She:
+ mes "";
+ mesn;
+ mesq l("She is a good friend of mine... We wanted to move together a few weeks before her accident but...");
+ next;
+
+ goto L_Quit2;
+
+L_Quest:
+ mes "";
+ mesn;
+ mesq l("I don't think that we are in a good place to talk about this...");
+ next;
+
+L_Quit:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Dan keeps silent since your last question."), 9);
+
+ close;
+
+L_Quit2:
+ mesn "Narrator";
+ mesc(l("Dan ends the conversation and resumes to write his letter."), 9);
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/devis.txt b/npc/000-2-1/devis.txt
new file mode 100644
index 00000000..5071dfb7
--- /dev/null
+++ b/npc/000-2-1/devis.txt
@@ -0,0 +1,16 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Reid
+// Vasily_Makarov
+// Description:
+// Sleeping and grumbling NPC.
+
+000-2-1,32,38,0 script Devis NPC_HAMMOC,{
+ asleep;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/hammock.txt b/npc/000-2-1/hammock.txt
new file mode 100644
index 00000000..3e188eed
--- /dev/null
+++ b/npc/000-2-1/hammock.txt
@@ -0,0 +1,125 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Animated hammock at the mid level of the ship.
+
+000-2-1,32,27,0 script #hammock1 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,32,25,0 script #hammock2 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,25,0 script #hammock3 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,27,0 script #hammock4 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,29,0 script #hammock5 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,34,0 script #hammock6 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,36,0 script #hammock7 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,38,0 script #hammock8 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,32,40,0 script #hammock9 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+000-2-1,37,40,0 script #hammock10 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
diff --git a/npc/000-2-1/knife.txt b/npc/000-2-1/knife.txt
new file mode 100644
index 00000000..b3e44eef
--- /dev/null
+++ b/npc/000-2-1/knife.txt
@@ -0,0 +1,47 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Qwerty Dragon
+// Description:
+// Knife on the table.
+// Variable:
+// ShipQuests_Knife
+// Values:
+// 0 Default, not taken.
+// 1 Knife taken.
+
+000-2-1,50,24,0 script #knife NPC_KNIVES,{
+ .@q = getq(ShipQuests_Knife);
+ if (.@q) close;
+
+ mesn "Narrator";
+ mesc(l("There are some knives on the table. Would you like to take one?"), 9);
+ next;
+
+ menu
+ l("Yes."), L_Give,
+ l("No."), -;
+
+ closeclientdialog;
+ close;
+
+L_Give:
+ mes "";
+ inventoryplace Knife, 1;
+
+ setq ShipQuests_Knife, 1;
+ getitem Knife, 1;
+
+ mesn "Narrator";
+ mesc(l("To open your inventory, use the F3 key or use your mouse to select it in the above menu in your client."), 9);
+ next;
+ mesc(l("When your inventory is open, you can equip an item by selecting it and clicking 'Equip'. You can do the same to unequip an item by clicking on 'Unequip'."), 9);
+ next;
+ mesc(l("Items have different effects. Some will heal you, some can be used as weapons or armor, and some can be sold for gold."), 9);
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/mapflags.txt b/npc/000-2-1/mapflags.txt
new file mode 100644
index 00000000..1543b585
--- /dev/null
+++ b/npc/000-2-1/mapflags.txt
@@ -0,0 +1 @@
+000-2-1 mapflag town
diff --git a/npc/000-2-1/peter.txt b/npc/000-2-1/peter.txt
new file mode 100644
index 00000000..499304c4
--- /dev/null
+++ b/npc/000-2-1/peter.txt
@@ -0,0 +1,302 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Ablu
+// Alastrim
+// Jesusalva
+// Qwerty Dragon
+// Reid
+// Vasily_Makarov
+// Description:
+// Rat hunter.
+// 4+2 bits array:
+// ShipQuests
+// Variable:
+// ShipQuests_Peter
+// Values is a bitmask:
+// 0 Doesn't know the quest.
+// 1 Task given. (To prevent bugs because zero is a valid instance id)
+// 2 Already completed the first stage
+// 4 Already completed the second stage
+// 8 Already completed the third stage
+// ...
+// =15 Completed every stage.
+// Setq2:
+// Number of killed Rattos:
+// & 1 - Ratto 1
+// & 2 - Ratto 2
+// & 4 - Ratto 3
+// & 8 - Ratto 4
+// = 15: All rattos killed
+// (Adding more monsters etc. is possible, but be careful with the == 15 checks)
+// Setq3:
+// Instance ID (so we can destroy it later if needed, and check it too)
+// Others:
+// .@q = Peter variable.
+// PETER_TIME = gettimetick(2) for daily
+// @peter = Control Variable
+// @pt_mob = Control Variable
+// @MAP_NAME$ = Control Variable
+// "000-2-2" - map with mobs.
+
+000-2-1,72,34,0 script AreaNPC NPC_HIDDEN,0,1,{
+ end;
+OnTouch:
+ doevent "Peter::OnPeterMain";
+ close;
+}
+
+000-2-1,70,35,0 script Peter NPC_RATTO_SAILOR,{
+ goto L_Main;
+
+OnPeterMain:
+L_Main:
+ .@q = getq(ShipQuests_Peter);
+ .@q2 = getq2(ShipQuests_Peter);
+ .@q3 = getq3(ShipQuests_Peter);
+ if (BaseLevel < 5) goto OnTooWeak;
+
+ if (!.@q || !isinstance(.@q3) || .@q3 <= 0) goto L_Task;
+ if (.@q2 < 15) goto L_ReturnFail;
+ dispbottom l("I am broken?! Please report! Debug data: @@ (@@)", .@q, .@q2);
+ close;
+
+OnGiveTask:
+L_Task:
+ if (!.@q)
+ setq ShipQuests_Peter, 1, 0, -1;
+ mesn;
+ mesq l("Hey there!");
+ next;
+ mesq l("I need somebody who can rid the hold of the ship of these rattos. Can you help me?");
+ next;
+
+ menu
+ l("Yeah, but what reward will I get?"), L_BonusTask,
+ l("Why not, I need to train anyway."), L_BonusTask,
+ l("No, they are way too dangerous for me!"), -;
+
+ mes "";
+ mesn;
+ mesq l("Hehe, hehe. Well, come back if you change your mind.");
+
+ close;
+
+// Friendly reminder that you have about 20 secs to finish
+OnLowTime:
+ if ((getmap() ~= "000-2-1") || (getmap() ~= "nard*"))
+ dispbottom l("I'm starting to feel dizzy... I shouldn't stay here much longer.");
+ end;
+
+// Minimum Quest Level (any difficulty setting) is on L_Main (and currently is 5)
+OnTooWeak:
+ mesn;
+ mesq l("I need someone to help me clean the edge of the ship, but you aren't strong enough for now.");
+
+ close;
+
+/*
+OnStop:
+ slide 72, 36;
+
+ mesn;
+ mesq l("You can't go there!");
+
+ close;
+*/
+
+// This is cast if player dies in Basement, but not automatically (bad design?)
+// instance_destroy() is being recklessy called here, some sanity check is good.
+OnReturnFail:
+L_ReturnFail:
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3); // This would allow players to try again at once, but is DANGEROUS!
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
+ mesn;
+ mesq l("I see it's not so easy to get rid of these rattos. Do you want to try again?");
+ next;
+
+ menu
+ l("Yeah, but I would like to make sure I get a reward."), L_BonusTask,
+ l("Why not, I need to train anyway."), L_BonusTask,
+ l("No, they are way too dangerous for me!"), -;
+
+ mes "";
+ mesn;
+ mesq l("Hehe, hehe. Well, come back if you change your mind.");
+
+ close;
+
+
+L_BonusTask:
+ mes "";
+ mesn;
+ mesq l("There are three kind of monsters which frequently or seldomly attacks our fair vessel.");
+ next;
+ mesn;
+ .@q = getq(ShipQuests_Peter);
+ if (!(.@q & 2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Tortuga));
+ mes l("I'll give you @@ GP for this job.", 500);
+ mes "";
+ }
+ if (!(.@q & 4)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 1000);
+ mes "";
+ }
+ if (!(.@q & 8)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Croc));
+ mes l("I'll give you @@ GP for this job.", 1500);
+ mes "";
+ }
+ // If you already took all three bounties, you can only repeat the quest daily
+ if (.@q == 15 && PETER_TIME <= gettimetick(2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 750);
+ } else if (.@q == 15) {
+ mes l("I don't need your help right now, but maybe tomorrow, who knows?");
+ close;
+ }
+ next;
+
+ select
+ l("I'm not feeling like it today... Sorry."),
+ rif(!(.@q & 2), l("I will take the @@ Bounty.", "Tortuga")),
+ rif(!(.@q & 4), l("I will take the @@ Bounty.", "Ratto")),
+ rif(!(.@q & 8), l("I will take the @@ Bounty.", "Croc")),
+ rif(.@q == 15, l("Why not, I need to train anyway."));
+
+ if (@menu == 1)
+ close;
+
+ @peter=@menu;
+
+ goto L_Start;
+
+// In Moubootaur Legends, there's a small tutorial about Hit'n'run here
+// I didn't add it here but that can be arranged
+L_Start:
+// Init Instance
+OnStartOutside:
+ .@ID=getcharid(0);
+ @MAP_NAME$="nard@"+str(.@ID); // Max 4 chars for map name
+ .@INSTID = instance_create("ratto@a"+(.@ID), getcharid(3), IOT_CHAR);
+ .@instanceMapName$ = instance_attachmap("000-2-2", .@INSTID, 0, @MAP_NAME$);
+
+ // Instance already exists, or something went wrong
+ if (.@instanceMapName$ == "") {
+ mesn;
+ mesq l("Actually, you just took a bounty, right?");
+ next;
+ mesn;
+ mesq l("Why don't you take a break? Breath in some fresh air. The basement is pretty damp.");
+ close;
+ }
+
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, .@INSTID;
+
+ // It'll be self-destroyed when time runs out (3 minutes)
+ instance_set_timeout(180, 180, .@INSTID);
+ instance_init(.@INSTID);
+
+ // Save in a less reliable way the challenge you took
+ if (@peter == 2) {
+ @peter=2;
+ @pt_mob=Tortuga;
+ } else if (@peter == 3) {
+ @peter=4;
+ @pt_mob=Ratto;
+ } else if (@peter == 4) {
+ @peter=8;
+ @pt_mob=Croc;
+ } else {
+ @peter=0;
+ @pt_mob=Ratto;
+ }
+
+ warp @MAP_NAME$, 48, 28;
+ // Control how much time you have left
+ addtimer(120000, "Peter::OnLowTime");
+ addtimer(140000, "Peter::OnTimeout");
+
+ // Spawn the Monsters
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto1Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto2Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto3Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto4Death";
+
+ dispbottom l("Okay, you can start!");
+ closeclientdialog;
+ close;
+
+// TODO: This is very reckless, instance_destroy() could possibly affect others
+// If you agree with me, we can force player to wait until instance expire on its
+// own (3 minutes after start) instead of allowing immediate retry. That's safer,
+// and code will end up looking like Mundane (exploiting attach_map failures)
+
+// (Or if you are set in disregarding this, just uncomment instance_destroy.)
+// (Don't blame me if server SIGSEGV's because that, though)
+OnTimeout:
+ if (!(getmap() ~= "000-2-2") && !(getmap() ~= "nard*"))
+ end;
+ warp "000-2-1", 72, 36;
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
+ mesn;
+ mesq l("Hey! Be careful. You can't stay in this basement for so long, you're going to get sick. Come outside and take a break, maybe you can try again later.");
+ close;
+
+// This is called by npc/000-2-2/ratto.txt and completes the quest
+// Just like OnReturnFail and OnTimeout, this recklessy destroys the instance
+// It's not _buggy_, it is just reckless. I would like a setting to restrict it
+// to destroy only instances owned by the char, or to destroy by name :p
+OnDone:
+ warp "000-2-1", 72, 36;
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ if (@peter)
+ setq ShipQuests_Peter, getq(ShipQuests_Peter)|@peter, 0, -1;
+
+ .@q = getq(ShipQuests_Peter);
+ mesn;
+ mesq l("Good job!") + " " + l("Here's your reward!");
+
+
+ // Before handling the rewards, we should be sure we'll handle daily loop.
+ // You're already in daily phase if @peter is zero.
+ // PS. This is not exactly "daily", this is actually a forced 24-hours wait.
+ if (!@peter) {
+ PETER_TIME=gettimetick(2)+24*60*60;
+ @peter=1; // This allows you to get 32 EXP from daily repeat. Tweak as needed.
+ }
+
+ // You get some EXP based on difficulty taken
+ getexp @peter*32, @peter;
+
+ // We don't need @peter anymore, so reuse it to give you GP rewards
+ switch (@peter) {
+ case 2: @peter=500; break;
+ case 4: @peter=1000; break;
+ case 8: @peter=1500; break;
+ default: @peter=750; break;
+ }
+
+ Zeny += @peter;
+ message strcharinfo(0), l("You receive @@ E!", @peter);
+
+ // Some cleanup. Shouldn't cause bugs but it's absence causes a ugly behavior.
+ deltimer("Peter::OnLowTime");
+ deltimer("Peter::OnTimeout");
+ @peter=0;
+ close;
+
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/000-2-1/q'onan.txt b/npc/000-2-1/q'onan.txt
new file mode 100644
index 00000000..c5ef0951
--- /dev/null
+++ b/npc/000-2-1/q'onan.txt
@@ -0,0 +1,15 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Vasily_Makarov
+// Description:
+// Sleeping and snoring NPC.
+
+000-2-1,53,38,0 script Q'Onan#000-2-1 NPC_ORC_SAILOR,{
+ asleep;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-1/story_save.txt b/npc/000-2-1/story_save.txt
new file mode 100644
index 00000000..68aacf60
--- /dev/null
+++ b/npc/000-2-1/story_save.txt
@@ -0,0 +1,30 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Scritpted save locations in 000-2-1 map.
+
+000-2-1,50,38,0 script #name3 NPC_FINAL_POINT,{
+ .@q_nard = getq(ShipQuests_Nard);
+ .@q_narr = getq(General_Narrator);
+
+ if(.@q_nard == 5 && .@q_narr < 1)
+ {
+OnClick:
+ narrator S_LAST_NEXT,
+ l("You lie in the bed."),
+ l("Your head is suddently heavy, your eyes are closing..."),
+ l("You fell asleep.");
+
+ warp "000-0-1", 26, 28;
+ }
+ else
+ {
+ savepointparticle "000-2-1", 50, 38;
+ }
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-2/_import.txt b/npc/000-2-2/_import.txt
new file mode 100644
index 00000000..81d32fdf
--- /dev/null
+++ b/npc/000-2-2/_import.txt
@@ -0,0 +1,5 @@
+// Map 000-2-2: Hold
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-2-2/doors.txt",
+"npc/000-2-2/mapflags.txt",
+"npc/000-2-2/ratto.txt",
diff --git a/npc/000-2-2/doors.txt b/npc/000-2-2/doors.txt
new file mode 100644
index 00000000..c97a7c5d
--- /dev/null
+++ b/npc/000-2-2/doors.txt
@@ -0,0 +1,75 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Alastrim
+// Jesusalva
+// Reid
+// Description:
+// Doors NPCs.
+
+000-2-2,48,29,0 script DoorUpwards NPC_HIDDEN,0,0,{
+
+OnTouch:
+ // Actually this will never work because Instanced map
+ if (mobcount("000-2-2","all") > 0) goto L_Warn;
+
+ goto L_Warp;
+
+L_Warn:
+ .@q = getq(ShipQuests_Peter);
+ if (.@q >= 15) goto L_Warp;
+
+ mesn "Narrator";
+ mesc(l("There are still some monsters left! Do you want to abort the quest?"), 9);
+ next;
+
+ menu
+ l("Yes."), L_Warp,
+ l("No."), -;
+
+ slide 48, 28;
+ closeclientdialog;
+ close;
+
+L_Warp:
+ warp "000-2-1", 72, 36;
+
+ deltimer("Peter::OnLowTime");
+ deltimer("Peter::OnTimeout");
+ closeclientdialog;
+ close;
+}
+
+// Besides the door, Alige is hiding himself and would rather not be disturbed
+000-2-2,24,31,0 script LeftDoor NPC_HIDDEN,0,0,{
+
+OnTouch:
+ mesn "Narrator";
+ mesc(l("It seems that you need a key to open this door."), 9);
+ next;
+ mesc(l("What do you want to do?"), 9);
+ next;
+
+ menu
+ rif(countitem(JohanneKey) > 0, l("Use the key.")), L_Warp,
+ l("Break the door."), L_Break,
+ l("Go away."), -;
+
+ closeclientdialog;
+ close;
+
+L_Break:
+
+ mes "";
+ mesn "Narrator";
+ mesc(l("You hear a loud scream. It must be the creaking of the wooden door..."), 9);
+
+ close;
+
+L_Warp:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Wait, it seems someone is blocking the door from the other side!"), 9);
+
+ close;
+}
diff --git a/npc/000-2-2/mapflags.txt b/npc/000-2-2/mapflags.txt
new file mode 100644
index 00000000..5202b332
--- /dev/null
+++ b/npc/000-2-2/mapflags.txt
@@ -0,0 +1 @@
+000-2-2 mapflag nosave 000-2-1,50,38
diff --git a/npc/000-2-2/ratto.txt b/npc/000-2-2/ratto.txt
new file mode 100644
index 00000000..d30ccd17
--- /dev/null
+++ b/npc/000-2-2/ratto.txt
@@ -0,0 +1,98 @@
+// Evol Script.
+// Author:
+// Ablu
+// Alastrim
+// Jesusalva
+// Reid
+// Description:
+// Ratto killer.
+// The only "lose" conditions are:
+// 1- dying, but this is not handled anywhere
+// 2- Time running out, Peter handles that automatically.
+// Note that if you die here, you won't be able to return and will need to
+// start the quest over again. (I wonder why it is not handled by an OnDeath event)
+// iirc, logout will automatically destroy the instance and clear timers, so it
+// doesn't needs the script writer to handle logout cleanup (only death).
+
+000-2-2,0,0,0 script RattosControl NPC_HIDDEN,{
+ end;
+
+// Each monster on the basement have its own respawn cycle.
+// We use a XOR (^) operand to mark that the killed monster is not dead anymore.
+// This is to reproduce as accurate as possible the legacy behavior of the quest.
+OnRatto1Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^1;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto1Death";
+ end;
+
+OnRatto2Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^2;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto2Death";
+ end;
+
+OnRatto3Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^4;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto3Death";
+ end;
+
+OnRatto4Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^8;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto4Death";
+ end;
+
+// When you kill a monster on basement, we must check the mob as dead, see if you
+// finally killed the last one and quest is complete, and add a timer to respawn it
+// after 1m25s (for flavor purposes, makes quest harder though)
+OnRatto1Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|1;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto1Respawn");
+ end;
+
+OnRatto2Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|2;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto2Respawn");
+ end;
+
+OnRatto3Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|4;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto3Respawn");
+ end;
+
+OnRatto4Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|8;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto4Respawn");
+ end;
+
+// This label is reached when all rattos are dead. We clear the respawn timers
+// (as we are going to delete the instance map anyway), warp you outside, and
+// from there onwards, Peter handles properly rewarding you.
+OnVictor:
+ deltimer("RattosControl::OnRatto1Respawn");
+ deltimer("RattosControl::OnRatto2Respawn");
+ deltimer("RattosControl::OnRatto3Respawn");
+ deltimer("RattosControl::OnRatto4Respawn");
+ addtimercount("Peter::OnTimeout", 5000);
+ addtimer(5000, "Peter::OnDone");
+ dispbottom l("It looks like all monsters were killed.");
+ end;
+}
diff --git a/npc/000-2-3/_import.txt b/npc/000-2-3/_import.txt
new file mode 100644
index 00000000..16842f77
--- /dev/null
+++ b/npc/000-2-3/_import.txt
@@ -0,0 +1,10 @@
+// Map 000-2-3: Nard's Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-2-3/_warps.txt",
+"npc/000-2-3/box.txt",
+"npc/000-2-3/elmo.txt",
+"npc/000-2-3/hammock.txt",
+"npc/000-2-3/mapflags.txt",
+"npc/000-2-3/nard.txt",
+"npc/000-2-3/piourocket.txt",
+"npc/000-2-3/sailors.txt",
diff --git a/npc/000-2-3/_warps.txt b/npc/000-2-3/_warps.txt
new file mode 100644
index 00000000..f5c0e1e7
--- /dev/null
+++ b/npc/000-2-3/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-3: Nard's Room warps
+000-2-3,19,27,0 warp #000-2-3_19_27 0,0,000-2-0,32,28
diff --git a/npc/000-2-3/box.txt b/npc/000-2-3/box.txt
new file mode 100644
index 00000000..30ea0a72
--- /dev/null
+++ b/npc/000-2-3/box.txt
@@ -0,0 +1,112 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Captain Nard dialogs.
+// Nard does the introduction with a small quest.
+// This quest is meant to teach the player how to use a weapon,and to bring food to the ship.
+// 4 bits array:
+// ShipQuests
+// Variable:
+// ShipQuests_Nard
+// Values:
+// 0 Introduction of the boxes and Nard. This is displayed when the player never spoke to Nard or his box.
+// 1 Nard spoke and gave access to the outdoor of the ship.
+// 2 Completed the Gugli quest.
+// 3 ChefGado Quest accepted.
+// 4 ChefGado Quest completed and "Introduction" chapter finalized.
+// 5 Reward taken from the box.
+
+000-2-3,25,24,0 script Box NPC_HAT_BOX,{
+ .@q = getq(ShipQuests_Nard);
+
+ mesn "Narrator";
+ mesc(l("Some Bandanas and Sailor Hats are inside this box."), 9);
+ next;
+ mesc(l("What do you wish to do?"), 9);
+ next;
+
+ menu
+ l("Take a Bandana."), -,
+ l("Nothing."), L_Quit;
+
+ if (.@q == 0) goto L_NoQuest;
+ if (.@q == 4) goto L_Give;
+ if (.@q > 4) goto L_Already;
+
+ setcamnpc "Nard";
+ mes "";
+ mesn "Nard";
+ mesq l("Please don't touch these hats, they are for crew members only.");
+
+ close;
+
+L_NoQuest:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Nard looks surprised and stops you."), 9);
+ next;
+
+ setcamnpc "Nard";
+ mesn "Nard";
+ mesq l("You like these hats, right?");
+ next;
+ mesq l("How about I ask you to help the crew? It would mean that you're one of us and that you will be able to get one of these hats.");
+ next;
+ mesq l("We need as many hands as possible to explore the island out there, and to get some new food.");
+ next;
+ mesq l("You could meet some of the other sailors this way, and... Getting this hat of course, will be a sign of you becoming part of our crew.");
+ next;
+ mesq l("What do you think?");
+ next;
+
+ menu
+ l("Why not, I've got plenty of free time."), -,
+ l("I think that I'm still a bit sick."), L_Quit;
+
+ mes "";
+ mesn "Nard";
+ mesq l("Great!");
+ next;
+ mesq l("I give you this key, it opens all the doors on this ship.");
+ next;
+ mesq l("Now go outside and talk with Gugli, he'll tell you what provisions we need.");
+ next;
+
+ inventoryplace JohanneKey, 1;
+ setq ShipQuests_Nard, 1;
+ getitem JohanneKey, 1;
+
+ close;
+
+L_Give:
+ setcamnpc "Nard";
+ mes "";
+ mesn "Nard";
+ mesq l("Congrats, you are now part of the crew. Thanks again for your help.");
+
+ inventoryplace Bandana, 1;
+
+ setq ShipQuests_Nard, 5;
+ getitem Bandana, 1;
+// Need to add a skill for the crew at this line.
+
+ close;
+
+L_Already:
+ setcamnpc "Nard";
+ mes "";
+ mesn "Nard";
+ mesq l("You already took a @@, please put this one back in the box.", getitemlink(Bandana));
+
+ close;
+
+L_Quit:
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
diff --git a/npc/000-2-3/elmo.txt b/npc/000-2-3/elmo.txt
new file mode 100644
index 00000000..831b07be
--- /dev/null
+++ b/npc/000-2-3/elmo.txt
@@ -0,0 +1,66 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Elmo's second dialog.
+
+000-2-3,27,27,0 script Elmo NPC_ELMO,{
+ function got_money {
+ speech S_LAST_NEXT,
+ l("Be patient a little while longer, in the next few days we will arrive at the port of Artis..."),
+ l("If you feel bored or like running around in circles, you may want to talk with the other sailors around here to get some tasks to do."),
+ l("From what I heard, my brother Gugli needs the help of as many people as possible in order to collect a lot of neat things that can be found on this island."),
+ l("Other than that, I don't know much about what else is going on, so directly asking the Cap'tain about it could be a good idea.");
+
+ goodbye;
+ }
+
+ if (getq(General_Narrator) > 0)
+ {
+ sailortalk;
+ }
+
+ if (getq(ShipQuests_ArpanMoney) >= 2)
+ {
+ got_money;
+ }
+
+ speech S_LAST_NEXT,
+ l("Hey you, sorry for leaving your room so quickly. I needed to speak with the captain about the food reserves. You know, now that we have a new mouth to feed, we need to check what we have."),
+ l("So, how is it going? Did you meet any other crew members yet?");
+
+ switch (select(l("Yes, Arpan gave me these clothes."), l("Not yet.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh good! Did he give you your money back as well?");
+
+ switch (select(l("Yes he did."), l("He told me nothing about that.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ok, be patient a little while longer, in the next few days we will arrive at the port of Artis...");
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Hehe, sometimes he gets his head in the clouds, You should go ask him about that.");
+ setq ShipQuests_ArpanMoney, 1;
+ break;
+ }
+
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You should go see them."),
+ l("You still got a few days before we arrive at the port, maybe you can learn something from them?");
+
+ break;
+ }
+
+ goodbye;
+
+OnInit:
+ .distance = 5;
+ end;
+}
diff --git a/npc/000-2-3/hammock.txt b/npc/000-2-3/hammock.txt
new file mode 100644
index 00000000..0ceeadbf
--- /dev/null
+++ b/npc/000-2-3/hammock.txt
@@ -0,0 +1,17 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Animated hammock at the top level of the ship.
+
+000-2-3,28,24,0 script #name5 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchRight;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
diff --git a/npc/000-2-3/mapflags.txt b/npc/000-2-3/mapflags.txt
new file mode 100644
index 00000000..b04a0fc9
--- /dev/null
+++ b/npc/000-2-3/mapflags.txt
@@ -0,0 +1 @@
+000-2-3 mapflag town
diff --git a/npc/000-2-3/nard.txt b/npc/000-2-3/nard.txt
new file mode 100644
index 00000000..05630e05
--- /dev/null
+++ b/npc/000-2-3/nard.txt
@@ -0,0 +1,341 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Captain Nard dialogs.
+// Nard does the introduction with a small quest.
+// This quest is meant to teach the player how to use a weapon,and to bring food to the ship.
+// 4 bits array:
+// ShipQuests
+// Variable:
+// 0 ShipQuests_Nard
+// 1 ShipQuests_Gugli
+// 2 ShipQuests_ChefGado
+// Values:
+// 00 Introduction of the boxes and Nard. This is displayed when the player never spoke to Nard or his box.
+// 01 Nard spoke and gave access to the outdoor of the ship.
+// 02 Completed the Gugli quest.
+// 03 ChefGado Quest accepted.
+// 04 ChefGado Quest completed and "Introduction" chapter finalized.
+// 05 Reward taken from the box.
+// 06 Intro finished
+// 10 Never talked with Gugli.
+// 11 Gugli gives you the task.
+// 12 Gave all of the boxes to Gugli.
+
+000-2-3,25,26,0 script Nard NPC_NARD,{
+ .@nard = getq(ShipQuests_Nard);
+ .@gugli = getq(ShipQuests_Gugli);
+ .@gado = getq(ShipQuests_ChefGado);
+
+L_Checker:
+ if (.@gado > 3 && .@nard == 3) goto L_ChefQuestComplete;
+ if (.@nard == 2) goto L_ChefQuestStart;
+ if (.@nard == 3) goto L_ChefQuestGiven;
+ if (.@nard == 4) goto L_Reward;
+ if (.@nard > 5) goto L_GoBackArtis;
+ if (.@nard > 4) goto L_Already;
+ if (.@gugli == 2) goto L_Done;
+ if (.@nard == 1) goto L_NotYet;
+
+ mesn;
+ mesq l("Hello.");
+ next;
+ mesq l("Let me introduce myself, I am Nard, captain of this ship.");
+ next;
+ mesq l("I am pleased to see that you have woken up and are active. Elmo came here to tell me this good news!");
+ next;
+
+ setcamnpc "Elmo";
+ mesn "Elmo";
+ mesq l("Oh... Err, yes I did, or, well, good day to you!");
+ next;
+ restorecam;
+
+ mesn;
+ mesq l("Hehehe, he is a bit nervous, please forgive him, it is not everyday we have a new member in the crew!");
+ next;
+ mesq l("So, how do you feel? I see that Julia did a marvelous job! You look like you're in good health now.");
+ next;
+
+L_Menu:
+ menu
+ l("I feel ok."), L_Ok,
+ rif(islegacyaccount(), l("I only want to reach Artis, can we skip this?")), L_Skip,
+ l("Who's this Julia?"), L_Julia,
+ l("I'm a bit sick..."), -;
+
+ mes "";
+ mesn;
+ mesq l("Oh, I was going to ask you if you wanted to help the crew search for some food and explore the island out there.");
+ next;
+
+L_MenuQuest:
+ menu
+ l("What do you need?"), -,
+ l("Is there a reward?"), L_NeedHead,
+ l("Wait, you never came here before?"), L_DrasilIsland;
+
+ mes "";
+ mesn;
+ mesq l("Oh! I like that sort of answer!");
+ next;
+ mesq l("We can use a helping hand on the island.");
+ next;
+
+ goto L_NeedContent;
+
+L_NeedHead:
+ mes "";
+ mesn;
+ mesq l("Of course there is a reward for your task.");
+ next;
+ mesq l("Hard work always pays off!");
+ next;
+ mesq l("What? It's not good enough?");
+ next;
+
+L_NeedContent:
+ mesq l("Our crew is like a family, and if you agree to help us, I would like to invite you to join our family!");
+ next;
+ mesq l("Hmm, I'll also give you one of these hats from the box near you, but only after you complete your task!");
+ next;
+ mesq l("Here, take this key, it opens all the doors on this ship.");
+ next;
+ mesq l("Now go outside and talk to Gugli, he'll tell you what we need.");
+ next;
+
+ inventoryplace JohanneKey, 1;
+
+ setq ShipQuests_Nard, 1;
+ getitem JohanneKey, 1;
+
+ close;
+
+L_Ok:
+ mes "";
+ mesn;
+ mesq l("Good to know.");
+ next;
+ mesq l("We have made a stop at a little island, before making it on to the port of Artis.");
+ next;
+ mesq l("It would be good for you to do some exercise, the ship isn't big enough for that.");
+ next;
+
+ goto L_SpecialTask;
+
+L_Julia:
+ mes "";
+ mesn;
+ mesq l("You have an awful case of amnesia.");
+ next;
+ mesq l("She is the nurse and shipkeeper of this ship.");
+ next;
+ mesq l("But most important, she is the one who took care of you when you were unconscious.");
+ next;
+
+L_SpecialTask:
+ mesq l("I know that you are just starting to feel better, but I'd like to give you a special task.");
+ next;
+
+ goto L_MenuQuest;
+
+L_DrasilIsland:
+ mes "";
+ mesn;
+ mesq l("To be honest, no, never.");
+ next;
+ mesq l("But discovering new territories is probably the best thing that can happen to sailors, don't you think?");
+ next;
+ mesq l("I'm really excited, this place reminds me of an ancient mythical tree, you might know what I'm talking about...");
+ emotion E_WINK;
+ next;
+ mesq l("As captain of this ship, I officially name this newly discovered land the ##BDrasil Island##b!");
+ next;
+ mesq l("Now, lets get back to business.");
+ next;
+
+ goto L_NeedContent;
+
+L_NotYet:
+ mesn;
+ mesq l("You still haven't completed your tasks.");
+ close;
+
+L_Done:
+ mesn;
+ mesq l("Hi @@.", strcharinfo(0));
+ next;
+ mesq l("Elmo and Gugli told me that you did all of the tasks outside, congrats!");
+
+ setq ShipQuests_Nard, 2;
+ next;
+ goto L_ChefQuestRedir;
+
+L_ChefQuestStart:
+ mesn;
+ mesq l("Elmo told me you are now considered family and are numbered among us in our activities on the island. I do so very much appreciate the efforts you did down there.");
+ next;
+
+L_ChefQuestRedir:
+ mesq l("Unfortunately, we still need help from you. This time it will be a delicate task, here onboard.");
+ next;
+ mesq l("Elmo brought reports to me about some frictions between my old and new lieutenants. You probably already met Julia and Chef Gado.");
+ next;
+ mesq l("They are each valued individuals and I need them both. In the past, I probably made my share of mistakes. I regret good management is so difficult. I was wondering if you could investigate and... Sort out this situation.");
+ next;
+
+ select
+ l("Of the two of them, who has 'good' on their side?");
+
+ mes "";
+ mesq l("I do not want to go pointing my finger at someone. I want to be honorable and fair, and I sense the same quality in you, so I put my trust in you. I am sure you will be able to judge and solve this troubling situation.");
+
+ setq ShipQuests_Nard, 3;
+
+ close;
+
+L_ChefQuestGiven:
+ mesn;
+ mesq l("It seems you still have some work to do.");
+
+ close;
+
+L_ChefQuestComplete:
+ mesn;
+ mesq l("Congratulations!");
+ next;
+ mesq l("You are now officially part of my crew! Thanks again for your help.");
+ next;
+ mesq l("Take your reward from the box next to my desk!");
+ next;
+
+ select
+ l("I will take it! Thank you captain!");
+
+ setq ShipQuests_Nard, 4;
+ getexp 50, 0;
+
+// Need to add a skill for the crew at this line.
+ mes "";
+
+L_Skip:
+ mesn;
+ mesq l("Oh noes! I can't believe it!");
+ next;
+ mesn;
+ mesq l("Well, I can bring you straight to Artis, but...");
+ next;
+ mesn;
+ mesc l("\"You will forsake items, quests and experience from the tuto-- %s from my whole crew and whatnot.\"", "##9"+l("*cough cough*")+"##1"), 1;
+ next;
+ mesn;
+ mesq l("Oh, and it is not only that.");
+ next;
+ mesn;
+ mesc l("\"This decision cannot be reverted. Which means you may have extreme difficulty and end up losing this char!\""), 1;
+ next;
+ mesn;
+ mesq l("And if that still wasn't enough to make you change your mind...");
+ next;
+ mesn;
+ mesc l("\"Deleting this char may (read: will) destroy the Legacy data associated to it!!\""), 1;
+ mesc l("i.e. Deleting the rEvolt char will delete the Legacy char associated to it. This includes levels and items."); // -- TRANSLATORS: i.e. = id est
+ next;
+ mesn;
+ mesq l("Are you absolutely, totally, certainly, completely sure, that you want a free, effortless ride to Artis, as weak and poorly equipped as you currently are?");
+ next;
+ mesc l("This decision cannot be reverted. Think with attention!"), 1;
+ select
+ l("Actually, lets do the tutorial."),
+ l("Lemme do Drasil Island!"),
+ l("YES, BRING ME TO ARTIS."),
+ l("I changed my mind.");
+ mes "";
+ if (@menu == 3) {
+ // Skip Drasil
+ setq ShipQuests_Julia, 2;
+ setq ShipQuests_Arpan, 3;
+ setq ShipQuests_Alige, 3;
+ setq ShipQuests_Peter, 15;
+ setq ShipQuests_Nard, 5; // NOTE: Completes the Beta
+ setq ShipQuests_Knife, 1;
+ setq ShipQuests_ArpanMoney, 3;
+ setq ShipQuests_Door, 1;
+ setq ShipQuests_Couwan, 2;
+ setq ShipQuests_TreasureChest, 1;
+ setq ShipQuests_Ale, 1;
+ setq ShipQuests_Astapolos, 1;
+ setq ShipQuests_Gulukan, 1;
+ setq ShipQuests_Jalad, 1;
+ setq ShipQuests_QMuller, 1;
+ setq ShipQuests_Tibbo, 1;
+ setq ShipQuests_Gugli, 2;
+ // Give Gado and Julia equal chances of winnning
+ setq ShipQuests_ChefGado, any(4,4,5,6);
+ // Automatically advance
+ mesc l("All Ship and Drasil Island Quests were auto-completed."), 1;
+ next;
+ goto L_Already;
+ }
+ mesn;
+ mesq l("Good! I was going to ask you if you wanted to help the crew search for some food and explore the island out there.");
+ next;
+ goto L_MenuQuest;
+
+L_Already:
+ speech
+ l("I recommend you to take a nap on the inferior level, we will soon leave this place.");
+
+ close;
+
+L_GoBackArtis:
+ checkclientversion;
+ speech S_LAST_NEXT,
+ l("Enough of this island?"),
+ l("Where would you like to go now?");
+ switch (select(l("Let's go to Artis."),
+ l("Tell me, where are we right now?"),
+ l("I would like to stay here a bit more.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Let's set sail then!");
+
+ savepoint "001-2-22", 50, 38;
+ if (!getmapxy(.@map$, .@x, .@y, 0))
+ {
+ warp "001-2-24", .@x, .@y;
+ }
+ else
+ {
+ warp "001-2-24", 22, 27;
+ }
+
+ closeclientdialog;
+ close;
+
+ case 2:
+ closeclientdialog;
+ npctalk3 l("This is Drasil Island, I named it after an ancient mythical tree.");
+ close;
+
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ok I stay here with my paperwork if you need my help.");
+
+ closeclientdialog;
+ close;
+ }
+
+L_Reward:
+ mesn;
+ mesq l("Hey! There's a reward for you in the box next to me!");
+
+ close;
+
+OnInit:
+ .distance = 5;
+ end;
+}
diff --git a/npc/000-2-3/piourocket.txt b/npc/000-2-3/piourocket.txt
new file mode 100644
index 00000000..e6ff2039
--- /dev/null
+++ b/npc/000-2-3/piourocket.txt
@@ -0,0 +1,29 @@
+// Evol scripts.
+// Author:
+// Ablu
+// Description:
+// Jumping piou.
+
+000-2-3,27,23,4 script #piourocket NPC_PIOU_ROCKET,{
+
+ .@now = gettimetick(2);
+
+ if (.@now - .last > 1)
+ {
+ .dir = 2;
+ .last = .@now;
+ specialeffect(26);
+ initnpctimer;
+ }
+
+ close;
+
+OnTimer1420:
+ .dir = 4;
+ stopnpctimer;
+ end;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/000-2-3/sailors.txt b/npc/000-2-3/sailors.txt
new file mode 100644
index 00000000..9287ed4b
--- /dev/null
+++ b/npc/000-2-3/sailors.txt
@@ -0,0 +1,47 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Qwerty Dragon
+// Reid
+// Description:
+// End of introduction with Nard and Elmo talking about the player.
+
+000-2-3,21,28,0 script AreaTop NPC_HIDDEN,0,5,{
+
+OnTouch:
+ if (getq(ShipQuests_Door) == 1) end;
+ setq ShipQuests_Door, 1;
+
+ setcamnpc "Elmo";
+ mesn "Elmo";
+ mesq l("So that's why we wanted to warn you. This sign on the raft indicates some relation to that guild.");
+ next;
+
+ setcamnpc "Nard";
+ mesn "Captain Nard";
+ mesq l("I see. Warn the other sailors about this. But any member of the Legion of Aemil would be our friend and ally.");
+ next;
+
+ setcamnpc "Elmo";
+ mesn "Elmo";
+ mesq l("I will.");
+ next;
+ mesq l("About the Legion of Aemil, I'm not sure about them, frankly.");
+ next;
+ mesq l("There are rumors going around that they did some monstrous things and that they are hiding quite a lot from us.");
+ next;
+
+ setcamnpc "Nard";
+ mesn "Captain Nard";
+ mesq l("This kind of talk should be taken with a grain of salt, but I agree and admit that I too am skeptical, so keep your eyes open.");
+ next;
+
+ mesq l("But... If Julia is right with the amnesia ... We don't need to worry. At least not yet.");
+ next;
+
+ setcamnpc "Elmo";
+ mesn "Elmo";
+ mesq l("Sure, cap'tain.");
+
+ close;
+}
diff --git a/npc/000-2-4/_import.txt b/npc/000-2-4/_import.txt
new file mode 100644
index 00000000..579e400a
--- /dev/null
+++ b/npc/000-2-4/_import.txt
@@ -0,0 +1,6 @@
+// Map 000-2-4: Alige's Hiding Place
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/000-2-4/_mobs.txt",
+"npc/000-2-4/_warps.txt",
+"npc/000-2-4/alige.txt",
+"npc/000-2-4/mapflags.txt",
diff --git a/npc/000-2-4/_mobs.txt b/npc/000-2-4/_mobs.txt
new file mode 100644
index 00000000..56230670
--- /dev/null
+++ b/npc/000-2-4/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-4: Alige's Hiding Place mobs
+000-2-4,30,30,1,1 monster Cuco 1020,1,80000,90000
diff --git a/npc/000-2-4/_warps.txt b/npc/000-2-4/_warps.txt
new file mode 100644
index 00000000..adfe9440
--- /dev/null
+++ b/npc/000-2-4/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 000-2-4: Alige's Hiding Place warps
+000-2-4,41,30,0 warp #000-2-4_41_30 0,0,000-2-2,25,31
diff --git a/npc/000-2-4/alige.txt b/npc/000-2-4/alige.txt
new file mode 100644
index 00000000..500a57a4
--- /dev/null
+++ b/npc/000-2-4/alige.txt
@@ -0,0 +1,38 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+
+000-2-4,38,22,0 script Alige#000-2-4 NPC_ALIGE_BARREL,2,2,{
+ npctalk3 l("Protect me, please...");
+ end;
+
+OnTouch:
+ .dir = LEFT;
+ stopnpctimer;
+ initnpctimer;
+ end;
+
+OnUnTouch:
+ .dir = UP;
+ stopnpctimer;
+ initnpctimer;
+ end;
+
+OnTimer190:
+ switch (.dir)
+ {
+ case UP:
+ .dir = DOWN;
+ break;
+ case LEFT:
+ .dir = RIGHT;
+ break;
+ }
+ stopnpctimer;
+ end;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/000-2-4/mapflags.txt b/npc/000-2-4/mapflags.txt
new file mode 100644
index 00000000..9c033937
--- /dev/null
+++ b/npc/000-2-4/mapflags.txt
@@ -0,0 +1 @@
+000-2-4 mapflag nosave 000-2-1,50,38
diff --git a/npc/001-1/_import.txt b/npc/001-1/_import.txt
new file mode 100644
index 00000000..18f8e363
--- /dev/null
+++ b/npc/001-1/_import.txt
@@ -0,0 +1,45 @@
+// Map 001-1: Artis
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-1/_mobs.txt",
+"npc/001-1/_warps.txt",
+"npc/001-1/artaxe.txt",
+"npc/001-1/beuss.txt",
+"npc/001-1/calypsan.txt",
+"npc/001-1/carmie.txt",
+"npc/001-1/chelios.txt",
+"npc/001-1/cookiemaster.txt",
+"npc/001-1/devis.txt",
+"npc/001-1/doors.txt",
+"npc/001-1/elmo.txt",
+"npc/001-1/enora.txt",
+"npc/001-1/eugene.txt",
+"npc/001-1/fexil.txt",
+"npc/001-1/flags.txt",
+"npc/001-1/flyingpiou.txt",
+"npc/001-1/harbours.txt",
+"npc/001-1/juscare.txt",
+"npc/001-1/katja.txt",
+"npc/001-1/koga.txt",
+"npc/001-1/lucas.txt",
+"npc/001-1/manhole.txt",
+"npc/001-1/mapflags.txt",
+"npc/001-1/marine.txt",
+"npc/001-1/merlin.txt",
+"npc/001-1/mouboo.txt",
+"npc/001-1/nalkri.txt",
+"npc/001-1/panels.txt",
+"npc/001-1/pious.txt",
+"npc/001-1/qonan.txt",
+"npc/001-1/qpid.txt",
+"npc/001-1/rowboat.txt",
+"npc/001-1/rowboathelper.txt",
+"npc/001-1/rumly.txt",
+"npc/001-1/salem.txt",
+"npc/001-1/shop.txt",
+"npc/001-1/sign.txt",
+"npc/001-1/sophialla.txt",
+"npc/001-1/taree.txt",
+"npc/001-1/treeleaf.txt",
+"npc/001-1/trees.txt",
+"npc/001-1/wateranimation.txt",
+"npc/001-1/xilaxa.txt",
diff --git a/npc/001-1/_mobs.txt b/npc/001-1/_mobs.txt
new file mode 100644
index 00000000..a2b6e5f1
--- /dev/null
+++ b/npc/001-1/_mobs.txt
@@ -0,0 +1,32 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-1: Artis mobs
+001-1,0,0,0,0 monster Piou 1002,2,15000,60000
+001-1,0,0,0,0 monster Piousse 1003,1,15000,150000
+001-1,174,34,11,15 monster Fluffy 1022,6,18000,100000
+001-1,199,48,2,5 monster Fluffy 1022,4,18000,100000
+001-1,174,34,11,15 monster Piou 1002,1,12000,60000
+001-1,35,62,1,4 monster Pikpik 1013,3,40000,20000
+001-1,26,96,3,2 monster Pikpik 1013,1,40000,20000
+001-1,42,137,4,1 monster Pikpik 1013,2,40000,20000
+001-1,45,136,0,0 monster Crocotree 1010,1,420000,240000
+001-1,70,136,0,0 monster Crocotree 1010,1,420000,240000
+001-1,37,126,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,34,130,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,41,129,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,36,77,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,37,79,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,39,73,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,43,70,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,48,71,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,40,67,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,46,65,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,152,26,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,152,32,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,155,37,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,158,29,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,203,51,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,198,50,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,199,55,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,185,65,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,191,63,0,0 monster Manana Tree 1017,1,420000,240000
+001-1,200,66,0,0 monster Manana Tree 1017,1,420000,240000
diff --git a/npc/001-1/_warps.txt b/npc/001-1/_warps.txt
new file mode 100644
index 00000000..c084792b
--- /dev/null
+++ b/npc/001-1/_warps.txt
@@ -0,0 +1,445 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-1: Artis warps
+001-1,51,80,0 script #001-1_51_80_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-4", 48, 40;
+close;
+
+OnUnTouch:
+ doevent "#001-1_51_80::OnUnTouch";
+}
+001-1,51,80,0 script #001-1_51_80 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,70,77,0 script #001-1_70_77_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-2", 38, 38;
+close;
+
+OnUnTouch:
+ doevent "#001-1_70_77::OnUnTouch";
+}
+001-1,70,77,0 script #001-1_70_77 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,51,65,0 script #001-1_51_65_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-0", 30, 34;
+close;
+
+OnUnTouch:
+ doevent "#001-1_51_65::OnUnTouch";
+}
+001-1,51,65,0 script #001-1_51_65 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,55,71,0 script #001-1_55_71_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-0", 37, 45;
+close;
+
+OnUnTouch:
+ doevent "#001-1_55_71::OnUnTouch";
+}
+001-1,55,71,0 script #001-1_55_71 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,168,98,0 script #001-1_168_98_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-16", 32, 35;
+close;
+
+OnUnTouch:
+ doevent "#001-1_168_98::OnUnTouch";
+}
+001-1,168,98,0 script #001-1_168_98 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,194,109,0 warp #001-1_194_109 0,0,001-2-21,20,28
+001-1,100,37,0 warp #001-1_100_37 0,0,001-2-19,32,39
+001-1,104,43,0 warp #001-1_104_43 0,0,001-2-19,41,49
+001-1,134,83,0 warp #001-1_134_83 0,0,001-2-28,60,31
+001-1,118,88,0 script #001-1_118_88_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-28", 29, 41;
+close;
+
+OnUnTouch:
+ doevent "#001-1_118_88::OnUnTouch";
+}
+001-1,118,88,0 script #001-1_118_88 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,182,74,0 script #001-1_182_74_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-18", 39, 35;
+close;
+
+OnUnTouch:
+ doevent "#001-1_182_74::OnUnTouch";
+}
+001-1,182,74,0 script #001-1_182_74 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,163,70,0 script #001-1_163_70_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-26", 28, 42;
+close;
+
+OnUnTouch:
+ doevent "#001-1_163_70::OnUnTouch";
+}
+001-1,163,70,0 script #001-1_163_70 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,132,67,0 script #001-1_132_67_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-15", 34, 45;
+close;
+
+OnUnTouch:
+ doevent "#001-1_132_67::OnUnTouch";
+}
+001-1,132,67,0 script #001-1_132_67 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,101,107,0 script #001-1_101_107_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-27", 35, 34;
+close;
+
+OnUnTouch:
+ doevent "#001-1_101_107::OnUnTouch";
+}
+001-1,101,107,0 script #001-1_101_107 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,89,65,0 script #001-1_89_65_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-7", 36, 45;
+close;
+
+OnUnTouch:
+ doevent "#001-1_89_65::OnUnTouch";
+}
+001-1,89,65,0 script #001-1_89_65 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,57,41,0 warp #001-1_57_41 0,0,001-2-33,34,45
+001-1,142,30,0 script #001-1_142_30_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-12", 34, 35;
+close;
+
+OnUnTouch:
+ doevent "#001-1_142_30::OnUnTouch";
+}
+001-1,142,30,0 script #001-1_142_30 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,128,30,0 script #001-1_128_30_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-1", 37, 40;
+close;
+
+OnUnTouch:
+ doevent "#001-1_128_30::OnUnTouch";
+}
+001-1,128,30,0 script #001-1_128_30 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,104,32,0 script #001-1_104_32_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-19", 41, 30;
+close;
+
+OnUnTouch:
+ doevent "#001-1_104_32::OnUnTouch";
+}
+001-1,104,32,0 script #001-1_104_32 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,107,49,0 script #001-1_107_49_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-20", 33, 34;
+close;
+
+OnUnTouch:
+ doevent "#001-1_107_49::OnUnTouch";
+}
+001-1,107,49,0 script #001-1_107_49 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,148,54,0 script #001-1_148_54_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-11", 46, 45;
+close;
+
+OnUnTouch:
+ doevent "#001-1_148_54::OnUnTouch";
+}
+001-1,148,54,0 script #001-1_148_54 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,135,49,0 script #001-1_135_49_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-10", 51, 44;
+close;
+
+OnUnTouch:
+ doevent "#001-1_135_49::OnUnTouch";
+}
+001-1,135,49,0 script #001-1_135_49 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,118,49,0 script #001-1_118_49_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-10", 27, 44;
+close;
+
+OnUnTouch:
+ doevent "#001-1_118_49::OnUnTouch";
+}
+001-1,118,49,0 script #001-1_118_49 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,49,96,0 script #001-1_49_96_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-31", 32, 39;
+close;
+
+OnUnTouch:
+ doevent "#001-1_49_96::OnUnTouch";
+}
+001-1,49,96,0 script #001-1_49_96 NPC_ARTIS_DOOR,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-1,198,61,0 warp #001-1_198_61 0,0,001-3-0,198,59
diff --git a/npc/001-1/artaxe.txt b/npc/001-1/artaxe.txt
new file mode 100644
index 00000000..f1d63d46
--- /dev/null
+++ b/npc/001-1/artaxe.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Legion NPC blocking the north road of Artis.
+
+001-1,90,31,0 script Artaxe NPC_ARTAXE,{
+ speech S_LAST_NEXT,
+ l("Sorry buddy, you can't pass by this way, we're moving some furniture."),
+ l("Come back later!");
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/beuss.txt b/npc/001-1/beuss.txt
new file mode 100644
index 00000000..fd334392
--- /dev/null
+++ b/npc/001-1/beuss.txt
@@ -0,0 +1,27 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Angry member of the Legion of Aemil.
+
+001-1,45,48,0 script Beuss NPC_BEUSS,{
+ stopnpctimer;
+ initnpctimer;
+ .dir = 4;
+ mesn;
+ mesq l("You seem pathetically weak. What is such boneless jelly like you doing around here?");
+
+ goto L_Close;
+
+L_Close:
+ close;
+
+OnTimer10000:
+ .dir = 2;
+ stopnpctimer;
+ end;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/calypsan.txt b/npc/001-1/calypsan.txt
new file mode 100644
index 00000000..46c4b84e
--- /dev/null
+++ b/npc/001-1/calypsan.txt
@@ -0,0 +1,104 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Dye seller, she sells and explain how works dye cards.
+// Version:
+// 2016.019 "Under Construction".
+// Variables:
+// ArtisQuests_Fexil
+// Quest states:
+// 0 -- not started
+// 1 -- Lloyd warned about the quest
+// 2 -- Fexil explain what he needs
+// 3 -- Fexil buy every fur that the pc bring to him
+
+001-1,47,126,0 script Calypsan#001-1 NPC_CALYPSAN,{
+
+ function explain_dyes {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Look at your equipment, can you guess what material it is made from?"),
+ l("Seek a colorant for that material:"),
+ l("Cotton, Silk, leather, ..."),
+ l("Zinc-Titanium Oxide, Phthalocyanides, Cadmiums, Lazulite..."),
+ l("Colorant is not the yeying color. Some wear out from light, others look great but inflict itai-itai, and others become spotty or wash-away."),
+ l("What yoiis should know:"),
+ l("1: The type of item yoiis want to dye."),
+ l("2: What material it is made from."),
+ l("3: Which colorants can dye it."),
+ l("4: How many cards your item can contain."),
+ l("Exemple for yoiis:"),
+ l("Take an @@ and a @@, yeye obtains a @@.", getitemlink(ArtisTankTop), getitemlink(RedCottonDye), getitemlink(ArtisTankTop, RedCottonDye)),
+ l("If yoiis wants to see a different use for the cards he can yeye for Resa at the light armor shop for a description of the styling cards.");
+ }
+
+ function sell_dye {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("For what kind of tissue?");
+ .@tissue_type = select(l("Cotton"), l("Silk"));
+
+ closeclientdialog;
+ switch (.@tissue_type)
+ {
+ case 1:
+ shop "Cotton#Dye001-1";
+ break;
+ case 2:
+ shop "Silk#Dye001-1";
+ break;
+ default:
+ consolemes(CONSOLEMES_ERROR, "Calypsan script error, tissue_type is incorrect");
+ break;
+ }
+ close;
+ }
+
+ speech S_LAST_NEXT,
+ l("Yoiis envies a rainbow in the sky?"),
+ l("It is possible to yeye your cloth with my beautiful dyes."),
+ l("What does yoiis want today?");
+
+ .@fexil = getq(ArtisQuests_Fexil);
+
+ do
+ {
+ select
+ rif(.@fexil == 1, l("Have you seen Fexil?")),
+ menuaction(l("Trade")),
+ l("How do these dyes work?"),
+ l("I want to make my own dyes."),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ setcamnpc "Fexil#001-1";
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh yeye did, his store is just beside me!"),
+ l("Yoiis should look there.");
+ restorecam;
+
+ break;
+ case 2:
+ sell_dye;
+ close;
+
+ case 3:
+ explain_dyes;
+ break;
+ case 4:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Yoiis is not yet ready to make his own dyes."),
+ l("But in the future I might be able to help you create some of your own.");
+ break;
+ }
+ } while (@menu != 5);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-1/carmie.txt b/npc/001-1/carmie.txt
new file mode 100644
index 00000000..e87e7fe6
--- /dev/null
+++ b/npc/001-1/carmie.txt
@@ -0,0 +1,68 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Reid
+// Description:
+// Carmie, walking NPC of the legion of Aemil on the center part of Artis.
+// Variables:
+// .@rand = Random number of sentences.
+
+001-1,86,66,0 script Carmie#001-1 NPC_RAIJIN_FEMALE_LEGION_ARTIS,{
+
+ legiontalk;
+
+ close;
+
+OnTimer1000:
+ domovestep;
+
+OnInit:
+ initpath "move", 89, 68,
+ "move", 89, 77,
+ "move", 84, 81,
+ "dir", LEFT, 0,
+ "wait", 2, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", RIGHT, 0,
+ "wait", 1, 0,
+ "move", 89, 85,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "dir", DOWN, 0,
+ "dir", RIGHT, 0,
+ "wait", 1, 0,
+ "move", 94, 81,
+ "dir", RIGHT, 0,
+ "wait", 2, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "move", 89, 76,
+ "move", 89, 68,
+ "dir", LEFT, 0,
+ "wait", 2, 0,
+ "dir", DOWN, 0,
+ "wait", 4, 0,
+ "dir", RIGHT, 0,
+ "wait", 2, 0,
+ "move", 92, 66,
+ "dir", RIGHT, 0,
+ "wait", 2, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "move", 86, 66,
+ "dir", LEFT, 0,
+ "wait", 2, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", RIGHT, 0,
+ "wait", 1, 0;
+
+ initialmove;
+ initnpctimer;
+ .distance = 5;
+}
diff --git a/npc/001-1/chelios.txt b/npc/001-1/chelios.txt
new file mode 100644
index 00000000..84af2de1
--- /dev/null
+++ b/npc/001-1/chelios.txt
@@ -0,0 +1,135 @@
+// Evol scripts.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// Blacksmith's assistant of Artis
+// Variables:
+// ArtisQuests_Enora
+// Values:
+// 0 Default.
+// 1 BlackSmith quest delivered.
+// 2 Chelios Quest given.
+// 3 Chelios Quest done.
+// 4 BlackSmith gave the sword.
+
+001-1,95,109,0 script Chelios NPC_CHELIOS,{
+ function give_small_quest;
+ function more_info;
+ function quest_completed;
+ function blacksmith_house;
+ function explain_weapons;
+
+ speech S_LAST_NEXT, l("Can I be of any help?");
+
+ do
+ {
+ .@enora = getq(ArtisQuests_Enora);
+ select
+ rif(.@enora == 1, l("I came to retrieve a package for Enora.")),
+ rif(.@enora == 3, l("I have your black iron.")),
+ rif(.@enora >= 2, l("Where is the Merchant Guild?")),
+ l("What is this building?"),
+ l("Why some of my weapons have a plus sign near them?"),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ give_small_quest;
+ break;
+ case 2:
+ quest_completed;
+ break;
+ case 3:
+ more_info;
+ break;
+ case 4:
+ blacksmith_house;
+ break;
+ }
+ } while (@menu != 5);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+
+function give_small_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Her sword... I'm having some trouble finishing it."),
+ l("You see, Enora asked me to do a black iron sword, unfortunately I ran out of the material needed, and..."),
+ l("Only Don and the Merchant Guild have that kind of material in stock. It's called black iron."),
+ l("It's better to deal with the Merchant Guild than the old man, Don has this ability to hammer down your enthusiasm in sparkling fury!"),
+ l("If Enora wants her sword now, I need to ask for your help.");
+
+ switch (select(l("Let's not keep her waiting."),
+ l("Not now.")))
+ {
+ case 1:
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I'll be here, come back when you'll be ready.");
+
+ return;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thank you very much!"),
+ l("Talk with Lloyd the Banker in the Merchant Guild, it's a big building in the northern side of Artis, at the top of the small hill.");
+
+ setq ArtisQuests_Enora, 2;
+
+ return;
+}
+
+function more_info {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It's the big building in northern Artis, at the top of a small hill."),
+ l("Take the east road that goes to the north and follow it until you are on top of the cliff."),
+ l("That part of the town is called the Gilded Hill, it's also where the Merchant Guild has its headquarters."), //rich hill
+ l("Lloyd still owes me, but beware of those money-grabbers, or they might sell your own teeth to you!");
+
+ return;
+}
+
+function quest_completed {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh... Awesome!"),
+ l("You were gone so I thought you let me down."),
+ l("Don gave me some black iron... after I asked him nearly ten times."),
+ l("But thank you anyway! I can refund him now!"),
+ l("Take the sword, and say hi to Enora for me!");
+
+ setq ArtisQuests_Enora, 4;
+
+ return;
+}
+
+function blacksmith_house {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Behind me? It's the Blacksmith House, the most renowned throughout Aemil."),
+ l("There are two shops inside, they are independent from the Merchant Guild of Artis."),
+ l("Now that I think about it, they are the only shops that are independent in Artis..."),
+ l("...it might be because of Don... he is the master blacksmith of this place and a model to me!");
+
+ return;
+}
+
+function explain_weapons {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Weapons do not level up. But the more you use them, the more used to them you become."),
+ l("As you start to wield them better, you will be able to draw better their full potential."),
+ l("Your proeficiency with a certain weapon is noted at the side of it. Naturally, you cannot obtain proeficiency by purchasing someone else's weapon.");
+ mesn;
+ speech S_LAST_NEXT,
+ l("By the way, I'll explain you how crafting works when I become less lazy.");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/001-1/cookiemaster.txt b/npc/001-1/cookiemaster.txt
new file mode 100644
index 00000000..984c02aa
--- /dev/null
+++ b/npc/001-1/cookiemaster.txt
@@ -0,0 +1,256 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Reid
+// Description:
+// Cookie NPC, beware, if you don't take your cookie, she'll keep it!
+// Variables:
+// General_Cookies
+// Values:
+// 0 Default, didn't get a cookie.
+// 1 Get a cookie.
+
+001-1,39,38,0 script Cookie Master NPC_COOKIE_MASTER,{
+ if ((countitem(517) == 0) && (getq(General_Cookies) == 1))
+ goto L_LostCookie;
+ if (getq(General_Cookies) == 1)
+ goto L_GetCookie;
+
+ mesn;
+ mesq l("Hey! Adventurer! Are you enjoying your life on Aemil?");
+ next;
+
+ select
+ l("Well in fact...");
+
+ mes "";
+ mesn;
+ mesq l("Shht shht!");
+ next;
+ mesq l("Don't tell me more, I know what you want...");
+ next;
+ mesq l("A cookie!");
+ next;
+
+ menu
+ l("I'd love one!"), -,
+ l("No thank you, I'm fine. I'll come back later."), L_Bye;
+
+ mes "";
+ mesn;
+ mesq l("Of course you do! Just listen carefully to these words my sweet.");
+ next;
+ mesq l("Cookies are a source of life.");
+ next;
+ mesq l("Cookies provide you strength, health and cuteness.");
+ next;
+ mesq l("Cookies are awesome, so am I.");
+
+ menu
+ l("Uhm... Your story seems..."), L_StorySeems,
+ l("Wait... That's not a proper place for a chef, what are you doing there?"), L_Presentation,
+ l("Exactly! Can I have one now?"), -;
+
+L_Check:
+ mes "";
+ mesn;
+ mesq l("Let me check my cookie list...");
+ next;
+
+// Beta3 Contributors.
+ if (strcharinfo(0) == "4144") goto L_Reward;
+ if (strcharinfo(0) == "Alige") goto L_Reward;
+ if (strcharinfo(0) == "enchilado") goto L_Reward;
+ if (strcharinfo(0) == "hal9000") goto L_Reward;
+ if (strcharinfo(0) == "Reid") goto L_Reward;
+ if (strcharinfo(0) == "Socapex") goto L_Reward;
+ if (strcharinfo(0) == "Kenny690") goto L_Reward;
+ if (strcharinfo(0) == "Nelson6e65") goto L_Reward;
+ if (strcharinfo(0) == "Steel Zenn") goto L_Reward;
+// Aurora1 Contributors.
+
+ mesq l("I'm sorry but I can't see your name anywhere.");
+ next;
+ mesq l("You see, folks around here that get my cookies have the distinction of being...");
+ next;
+
+ menu
+ l("Seriously? It's just a cookie you know... Tell me what I should do to get one."), L_BTaskExpanation,
+ l("Yes, yes I know... Too bad then. See you soon!"), L_Bye;
+
+L_StorySeems:
+ mes "";
+ mesn;
+ mesq l("What about my story?");
+ next;
+
+ menu
+ l("It's interesting and exciting at the same time!"), -,
+ l("Honestly, it's quite far-fetched according to me."), L_Kick;
+
+ mes "";
+ menu
+ l("Too bad. I'm not hungry enough for these cookies of yours. Maybe I'll come back later."), L_Bye,
+ l("How can I get one of these cookies?"), -;
+
+ mes "";
+ mesn;
+ mesq l("It looks like you are curious, am I right?");
+ next;
+ mesq l("Well, if you ever do want to join: 'Ye Merry Club Of Thee Bequeathed With Cookies'...");
+ next;
+
+L_BTaskExpanation:
+ mes "";
+ mesn;
+L_TaskExpanation:
+ mesq l("You'll first need to help my friends.");
+ next;
+ mesq l("It is them, after all, who have the ultimate decision as to those I can give my cookies to.");
+ next;
+
+ menu
+ l("So you're under the control of a dictatorship? That's... reassuring!"), L_Control,
+ l("Who are these friends?"), L_Friends;
+
+L_Friends:
+ mes "";
+ mesn;
+ mesq l("Shht shht!");
+ next;
+ mesq l("Don't say it so loudly, other people could hear us.");
+ next;
+ mesq l("My friends are... Well, you know... The creators.");
+ next;
+ mesq l("I can't give you a cookie for free. But I can give you this hint for how you may be added to my list.");
+ next;
+ mesq l("Now listen to and ponder my words...");
+ next;
+ mesq l("If you see weird things here and there, or things that just shouldn't be, or even in your minds eye, things that you would like to see...");
+ next;
+ mesq l("Simply contact them, by forum or wispers or irc. When you are helpful and kind, they respond in kind. And in time they may surely add you to my cookie list!");
+ next;
+
+ mesn "Narrator";
+ mesc(l("This Cookie Master rewards people who contribute and develop this world."), 9);
+ next;
+ mes col(l("If you want to be rewarded, help us in making this world a better place."), 9);
+ next;
+ mesc(l("When you see something that looks more like a bug than a feature, report it on https://forums.themanaworld.org or try to contact a game contributor."), 9);
+ next;
+ mesc(l("Any contribution to the game (translations, graphics creation/edition, concepts, coding/scripting, etc...) is rewarded!"), 9);
+
+ mes "";
+ mesn;
+ mesq l("So, do you still want a cookie?");
+ next;
+
+ menu
+ l("I wish I helped your friends, because I'd really, really like a cookie."), -,
+ l("You tell me. Do I deserve a cookie?"), L_Check;
+
+ mes "";
+ mesn;
+ mesq l("Don't worry, I'm sure you will help them soon enough!");
+ next;
+
+ goto L_Bye;
+
+L_Presentation:
+ mes "";
+ mesn;
+ mesq l("For a chef? Who said I was a... Oh right, I am.");
+ next;
+ mesq l("I was sent here with a task. I can give you a perfect, wonderful, magnificent, superbly well shaped... Cookie!");
+ next;
+ mesq l("But...");
+ next;
+
+ goto L_TaskExpanation;
+
+L_Reward:
+ mesq l("Yes! @@ is written on my cookie list.", strcharinfo(0));
+ next;
+ mesq l("That's quite surprising... You don't look very helpful.");
+ next;
+ mesq l("Anyway, here, have a cookie!");
+
+ inventoryplace DeliciousCookie, 1;
+
+ setq General_Cookies, 1;
+ getnameditem DeliciousCookie, strcharinfo(0);
+ npctalk3 l("You receive a @@!", getitemlink(DeliciousCookie));
+
+ next;
+ mesq l("I'm sure you'll appreciate its effect, but be careful, these cookies are rare, and you'll need to help the community again before being able to receive another one.");
+ next;
+
+ goto L_Bye;
+
+L_Control:
+ mes "";
+ mesn;
+ mesq l("C'mon, don't be like that and loosen up! Don't you want to know who's behind all of this?!");
+ next;
+
+ menu
+ l("Why not, this might get interesting."), L_Friends,
+ l("Fine, tell me, who are these all important friends of yours?"), -,
+ l("No, and I gotta go, see you."), L_Kick;
+
+ mes "";
+ mesn;
+ mesq l("Don't belittle me, my work is deserving of the highest esteem.");
+ next;
+
+L_Kick:
+ closeclientdialog;
+
+ npctalk3 l("No cookie for you!");
+ warp "001-1", 39, 41;
+
+ close;
+
+L_GetCookie:
+ mesq l("Hey, I'm not a Keebler Elvis! You won't have another one by stalking me like that!");
+ next;
+ mesq l("If you want another cookie, you know what to do!");
+ next;
+ mesq l("Now, move!");
+ next;
+
+ goto L_Bye;
+
+L_LostCookie:
+ mesq l("Hey, how was the...");
+ next;
+ mesq l("Wait a minute, where's the cookie I gave you?");
+ next;
+ mesq l("I'm talking about the cookie inside which I put all my love!");
+ next;
+ mesq l("The best, the wonderful, the most choice cookie among all others, the...");
+ next;
+ // Angry emote
+ mesq l("Grr...");
+ next;
+ mesq l("You're lucky that I'm a generous person, here's another one.");
+ next;
+ mesq l("This is the last one. If you use it again out of clumsiness, I will use your soft moist parts in the concoction of my next cookie batch.");
+ next;
+
+ inventoryplace DeliciousCookie, 1;
+ getnameditem DeliciousCookie, strcharinfo(0);
+
+ npctalk3 l("You receive a @@!", getitemlink(DeliciousCookie));
+
+L_Bye:
+ closeclientdialog;
+
+ npctalk3 l("See you later!");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/devis.txt b/npc/001-1/devis.txt
new file mode 100644
index 00000000..d3af5956
--- /dev/null
+++ b/npc/001-1/devis.txt
@@ -0,0 +1,99 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// La Johanne crew member.
+
+001-1,193,109,0 script Devis#001-1 NPC_DEVIS_ARTIS,{
+
+ function say_random_greeting {
+ .@enora = getq(ArtisQuests_Enora);
+ if (.@enora == 0)
+ {
+ speech
+ l("Enora, from the Legion of Aemil, has been warned that you were aboard."),
+ l("She is waiting for you on the dock.");
+
+ return;
+ }
+
+ .@rand = rand(5);
+ if (.@rand == 0) goodbye;
+ else if (.@rand == 1)
+ {
+ speech S_LAST_NEXT,
+ l("A sunny and hot day,"),
+ l("a quiet place,"),
+ l("a ground!"),
+ l("What else do you need?");
+ }
+ else if (.@rand == 2) npctalk3 l("A-hoy matey!");
+ else if (.@rand == 3) npctalk3 l("We are glad captain Nard has let you join the crew!");
+ else if (.@rand == 4) npctalk3 l("Howdy?");
+
+ return;
+ }
+
+ function face_to_PC {
+ getmapxy(.@map$, .@cx, .@cy, 0);
+ @Devis_old_dir = .dir;
+ npc_turntoxy(.@cx, .@cy);
+
+ return;
+ }
+
+ function local_close {
+ if (@Devis_old_dir > 0)
+ {
+ .dir = @Devis_old_dir;
+ }
+ npc_resumemove;
+
+ close;
+ }
+
+ @Devis_old_dir = -1;
+
+ npc_pausemove;
+ face_to_PC;
+ say_random_greeting;
+ local_close;
+
+OnTimer1000:
+ dographmovestep;
+
+OnInit:
+ .distance = 5;
+ initmovegraph "start_pos", 193, 109,
+ "dock_ent", 194, 109,
+ "dock_right", 192, 114, 195, 115,
+ "dock_left", 151, 103, 160, 106,
+ "dock_bot", 161, 119, 163, 127,
+ "dock_top", 184, 91, 195, 92,
+ "ship_ent", 19, 28,
+ "ship_sit", 28, 26,
+ "dock_mid", 174, 105;
+
+ setmovegraphcmd "start_pos", "dock_mid", 1, "dir 0; wait 2",
+ "dock_ent", "dock_right", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "dock_ent", "dock_mid", 2, "moveon",
+ "dock_bot", "dock_left", 1, "dir 6; wait 8",
+ "dock_bot", "dock_mid", 2, "moveon",
+ "dock_left", "dock_bot", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "dock_left", "dock_mid", 2, "moveon",
+ "dock_right", "dock_ent", 1, "warp 001-2-21 ship_ent",
+ "dock_right", "dock_mid", 2, "moveon",
+ "dock_top", "dock_mid", 1, "moveon",
+ "dock_mid", "dock_bot", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "dock_mid", "dock_right", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "dock_mid", "dock_left", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "dock_mid", "dock_top", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "dock_mid", "dock_ent", 2, "warp 001-2-21 ship_ent",
+ "ship_ent", "ship_sit", 1, "dir 4; sit; wait 14; stand; wait 1",
+ "ship_sit", "ship_ent", 1, "warp 001-1 dock_ent";
+
+ firstmove "wait 8", "start_pos";
+ initnpctimer;
+}
+
diff --git a/npc/001-1/doors.txt b/npc/001-1/doors.txt
new file mode 100644
index 00000000..c4288328
--- /dev/null
+++ b/npc/001-1/doors.txt
@@ -0,0 +1,61 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Doors warp and animations in map 001-1
+//
+
+001-1,57,41,0 script #Warp20 NPC_HIDDEN,0,0,{
+OnTouch:
+ .@enora = getq(ArtisQuests_Enora);
+
+ if (.@enora < 4)
+ {
+ narrator S_LAST_NEXT,
+ l("The door to the legion building is temporarily closed.");
+ }
+ else
+ {
+ warp "001-2-33", 34, 46;
+ }
+
+ closeclientdialog;
+ close;
+
+OnUnTouch:
+ doevent "#Door20::OnUnTouch";
+}
+
+001-1,57,41,0 script #Door20 NPC_ARTIS_DOOR,2,3,{
+ close;
+
+OnTouch:
+ .@enora = getq(ArtisQuests_Enora);
+ .@legion = getq(Artis_Legion_Progress);
+ .@brotherhood = getq(General_Brotherhood);
+ if (.@enora < 4)
+ {
+ setfakecells 57, 41, 1;
+ end;
+ }
+ if (.@legion == 6 && !.@brotherhood)
+ addtimer 30, "Sophialla#001-1::OnLegionComplete";
+ setfakecells 57, 41, 0;
+ doorTouch;
+
+OnUnTouch:
+ .@enora = getq(ArtisQuests_Enora);
+ if (.@enora < 4)
+ {
+ end;
+ }
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
diff --git a/npc/001-1/elmo.txt b/npc/001-1/elmo.txt
new file mode 100644
index 00000000..a8c3fb3d
--- /dev/null
+++ b/npc/001-1/elmo.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Sailor of Nard's La Johanne ship.
+
+001-1,185,107,0 script Elmo#001-1 NPC_ELMO_ARTIS,{
+ speech
+ l("Oh hey!"),
+ l("If you feel bored or anxious, you can always ask some of the people around Artis if they need your help.");
+ l("It's better than running around in circles doing nothing.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
diff --git a/npc/001-1/enora.txt b/npc/001-1/enora.txt
new file mode 100644
index 00000000..d676407f
--- /dev/null
+++ b/npc/001-1/enora.txt
@@ -0,0 +1,461 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Newbie guide for Artis.
+// Variables:
+// ArtisQuests_Enora
+// Values:
+// 0 Default.
+// 1 BlackSmith quest delivered.
+// 2 Chelios Quest given.
+// 3 Chelios Quest done.
+// 4 BlackSmith gave the sword.
+// 5 Light Armor Shop quest delivered.
+// 6 Light Armor Shop gave the cloths.
+// 7 Market quest delivered.
+// 8 Q'Pid merchant.
+// 9 Market gave the potion.
+// 10 Hill quest delivered.
+// 11 Fluffy killed.
+
+001-1,176,113,0 script Enora#001-1 NPC_HUMAN_FEMALE_NOOB,{
+
+ function enora_don {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Don is renowned throughout the entire land of Aemil for his blacksmithing skills, and he is here, in Artis."),
+ l("It's a great honor for us, at the Legion, to hold the security of his business!"),
+ l("If you search for him you should look in the west of the city, it's the first house just after the left bridge, you can't miss it!"),
+ l("Chelios, his apprentice, practices outside, mostly.");
+
+ return;
+ }
+
+ function enora_legion {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("The Legion of Gasaron are a group of warriors who vowed to protect and serve their neighbours."),
+ l("We hold various training sessions, and also have a task board with a heap of things to do for the city and its surroundings."),
+ l("It's a good place to earn money, it can also help you to travel throughout the land!"),
+ l("Each big city hosts a Legion building, Artis' building is located in the north-west.");
+
+ return;
+ }
+
+ function enora_light_armor {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("The light armor shop is ran by Resa, she is part of the Merchant Guild of Artis."),
+ l("She is very skilled when it comes to weaving an ordinary piece of cloth into a wonderful work of art!"),
+ l("Her shop is on the west side of the city, between the Legion building and the library.");
+
+ return;
+ }
+
+ function enora_market {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("The market is located in the south-east of Artis, it is known as Merchant Guild's exhibit."),
+ l("You need to be a member of the Merchant Guild to have a chance there."),
+ l("And I bet you don't know who is in charge of monitoring the security of this place?");
+
+ switch (select(l("The Legion?"), l("I don't know.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You hit the nail on the head, it's the Legion of Gasaron!"),
+ l("Our main responsibility in the city is to protect the Merchant Guild.");
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Cat got your tongue?"),
+ l("..."),
+ l("Your brain liquified to match the level of a piou! It's the Legion of Gasaron.");
+ break;
+ }
+ return;
+ }
+
+ function enora_hill {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Go north from here until you find the dock warehouse, cross the bridge to the west side of the canal, continue north until you reach another bridge then cross it to the east side of the canal."),
+ l("You should arrive at a park with a hill nearby.");
+
+ return;
+ }
+
+ function enora_memories {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It's so exciting to meet somebody with amnesia!"),
+ l("Can't you remember anything at all? Or do you have some memories of your past?"),
+ l("What happens when you try to think about it?"),
+ l("Does your mind go all fuzzy or does it feel like your head is going to explode??"),
+ l("Try doing that now!");
+
+ switch (select(l("Okay, but there won't be any explosions."),
+ l("Don't get too excited about it...")))
+ {
+ case 1:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You concentrate and try to summon old memories from within your mind."),
+ l("You feel numb and everything around you looks foggy, but you can recall the feeling of the cold hard wood of your raft on a stormy night."),
+ l("A headache hits you and you lose your concentration.");
+
+ speech S_LAST_NEXT,
+ l("So? You haven't exploded yet! Are you getting anything?");
+
+ select(l("Not really. All I got was a headache..."));
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It's like your memories are locked away in your head! Cool!");
+
+ break;
+ case 2:
+ mes "";
+ break;
+ }
+
+ speech S_LAST_NEXT,
+ l("Ok, sorry. Back to our fluffies.");
+
+ return;
+ }
+
+ function enora_reward {
+ .@exp_reward = getarg(0);
+ .@zeny_reward = getarg(1);
+
+ quest_xp(.maxLevel, .@exp_reward);
+ quest_gp(.maxLevel, .@zeny_reward);
+
+ narrator S_LAST_NEXT,
+ l("You received @@ EXP and @@ E.", .@exp_reward, .@zeny_reward);
+
+ // This is silent (can be caught as a string variable)
+ faction_addrep("Legion", 10);
+ return;
+ }
+
+ function enora_first_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You probably don't have much business in this city as you don't remember who you are."),
+ l("So I was going to ask if maybe you would be interested in giving me a hand with a few errands.");
+
+ switch (select(l("I guess so. What's in it for me?"),
+ l("Of course! What do you need?")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Some tasks will help you become aquainted with Artis. Trust me.");
+ break;
+ case 2:
+ mes "";
+ break;
+ }
+
+ speech S_LAST_NEXT,
+ l("I asked Don our blacksmith to prepare a black iron sword for morning, he should be done by now."),
+ l("Go meet him, and take the package to me, it's an easy task."),
+ l("You will be able to find Don's house in the west of the city, it's the first house just after the bridge on the left, you can't miss it!"),
+ l("A young apprentice called Chelios might be waiting outside, speak to him, and return the package to me.");
+ emotion E_HAPPY;
+
+ setq ArtisQuests_Enora, 1;
+
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ function enora_second_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thank you for this commission, Chelios is as good as Don when it comes to forging metal."),
+ l("By the way, did you ever talk with Don?"),
+ l("If so, I hope that he didn't give you any hard time, sometimes he can get up on the wrong side of the bed he becomes an embittered and grumpy old man..."),
+ l("Poor Chelios, I don't envy him..."),
+ l("So, everything went fine?");
+
+ switch (select(l("Chelios managed to do excellent work."),
+ l("The old man seemed to be senile.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("Fine, let's see his work...");
+ narrator S_LAST_NEXT, l("Enora is carefully inspecting the sword.");
+ speech S_LAST_NEXT,
+ l("Excellent!"),
+ l("The detail and craftsmanship that went into this sword can only be accomplished by the most practiced of blacksmiths.");
+
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He may not have all of his wits but keep in mind one thing:"),
+ l("Don is renowned throughout the entire land for his blacksmith skills, and he is here, in Artis."),
+ l("It's a great honor for us, at the Legion, to hold the security of his business!");
+
+ break;
+ }
+
+ speech S_LAST_NEXT,
+ l("After this small overview of Artis, what do you think of our city?"),
+ l("The Legion of Gasaron is in charge of the security of the intramural part of our cities."),
+ l("The control and administration of the cities passes hands sometimes. You may find the Mana Order or the Brotherhood in charge instead of us at some point!"),
+ l("But we are quite lucky here, outside of some tipsy travelers there are no big problems around here, it's not like the capital, Esperia."),
+ l("Now that I think about it, I have another task for you. I asked Resa from the light armor shop to craft me some new clothes, she is a bit far from here, I can't go there because I need to watch the dock."),
+ l("Her shop is on the west side of the city, between the Legion building and the library.");
+
+ setq ArtisQuests_Enora, 5;
+ enora_reward(60, 100);
+
+ closeclientdialog;
+ npctalk3 l("Thank you very much!");
+ close;
+ }
+
+ function enora_third_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Look how splendid this @@ is!", getitemlink(ArtisTankTop, CamelCottonDye)),
+ l("It's nearly as good as one from Esperia, have you ever been there?"),
+ l("Ah... Sorry, I forgot, again."),
+ l("I mean, you forgot... Well."),
+ l("If you ever find the time, pass by Esperia, it's the greatest city in all of Gasaron!"),
+ l("You can find the building of the Legion of Gasaron there, like in any other city, but Esperia is important for us as our headquarters are there.");
+
+ do
+ {
+ .@q = select(l("Do you still need help?"),
+ l("What is this \"legion\"?"));
+ switch (.@q)
+ {
+ case 1:
+ break;
+ case 2:
+ enora_legion;
+ break;
+ }
+ } while (.@q == 2);
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh yes, I have one last errand for you, Q'Pid in the market sells potions."),
+ l("It has been some days now since I asked her for a box of @@s, but she hasn't delivered anything yet.", getitemlink(PiberriesInfusion)),
+ l("Please try to figure out what went wrong with this order and bring me those potions."),
+ l("You will be able to find her in the market in the south-west of Artis.");
+
+ setq ArtisQuests_Enora, 7;
+ enora_reward(40, 125);
+
+ closeclientdialog;
+ npctalk3 l("Thank you very much!");
+ close;
+ }
+
+ function enora_fourth_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Awesome!");
+
+ speech S_LAST_NEXT,
+ l("I have one more task for you. Trozz, another member of the Legion, sent me a letter earlier today."),
+ l("Some citizens are worried about the growing number of Fluffies on the hill of Artis."),
+ l("Children play there and can be badly hurt if they get too close to a Fluffy's nest."),
+ l("It would have been easy for me to handle it but if you do it, you can earn some respect by killing Fluffies instead of their natural predators!"),
+ l("Besides, I need to be here to watch out for thieves while La Johanne is docked."),
+ l("You look confident. I will give you my old gear as reward and acknowledgment for your time... and take these potions as well!");
+
+ set ArtisFluffyKilled, 0;
+
+ inventoryplace TrainingGladius, 3;
+ getitem TrainingGladius, 1;
+ getitem2 ArtisTankTop, 1, 1, 0, 0, 5005, 0, 0, 0;
+ getitem PiberriesInfusion, 5;
+ setq ArtisQuests_Enora, 10;
+ enora_reward(80, 175);
+
+ speech S_LAST_NEXT,
+ l("Do you know where the hill is?");
+
+ switch (select(l("Yes I do."),
+ l("Please guide me.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Perfect! I will wait for you here.");
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Follow the up-stream and cross the canal twice using the two bridges north from here."),
+ l("The hill is located on the north-east of Artis.");
+ break;
+ }
+
+ closeclientdialog;
+ npctalk3 l("Thank you very much!");
+ close;
+ }
+
+ function enora_hill_cleaned {
+ if (getq2(ArtisQuests_Enora) < 9)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh no, you still have @@ Fluffies to kill.", 10 - getq2(ArtisQuests_Enora));
+
+ return;
+ }
+ else if (getq2(ArtisQuests_Enora) < 10)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Only one more Fluffy to kill and it's done!");
+
+ return;
+ } else if (getq(ArtisQuests_Enora) == 10) {
+ inventoryplace TreasureKey, 1;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I cannot find the words to express my gratitude for your hard work."),
+ l("Keep the sword and the jacket, you deserved them!"),
+ l("You now also have access to the Legion building. Good job, you earned it."),
+ l("We hold various training sessions, and also have a task board with a heap of things to do for the city and its surroundings."),
+ l("It's a very good place if you want to make some more money.");
+ emotion E_WINK;
+
+ if (getq(ArtisQuests_Enora) == 10)
+ {
+ setq ArtisQuests_Enora, 11;
+ enora_reward(140, 500);
+ getitem TreasureKey, 1;
+ mesn;
+ mesq l("Also, here is a %s. If you find a Treasure Chest somewhere, you can open it with this!", getitemlink(TreasureKey));
+ next;
+ }
+
+ return;
+ }
+
+ function enora_quest_complete {
+ switch (getq(ArtisQuests_Enora))
+ {
+ case 4:
+ enora_second_quest;
+ break;
+ case 6:
+ enora_third_quest;
+ break;
+ case 9:
+ enora_fourth_quest;
+ break;
+ default:
+ break;
+ }
+
+ return;
+ }
+
+ function enora_paid_potions {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Are you sure that these are my potions?");
+
+ if (askyesno() == ASK_YES)
+ {
+ delitem PiberriesInfusion, 5;
+ enora_fourth_quest;
+ }
+
+ return;
+ }
+
+ if (getq(ArtisQuests_Enora) == 0)
+ {
+ speech S_LAST_NEXT,
+ l("Hey! You must be @@.", strcharinfo(0)),
+ l("Julia told me how they found you in the sea, on a raft with a logo of..."),
+ l("...I mean log! Made of log!"),
+ l("I also heard you lost all your memories? That's a shame."),
+ l("I'm sure you would have some interesting stories to tell!");
+ }
+ else
+ {
+ speech S_LAST_NEXT,
+ l("Hey @@!", strcharinfo(0)),
+ l("What brings you here today?");
+ }
+
+ do
+ {
+ .@q = getq(ArtisQuests_Enora);
+ select
+ rif(.@q == 0, l("She told me that you had some tasks for me.")),
+ rif(.@q == 4 || .@q == 6 || .@q == 9, l("I have your package.")),
+ rif(.@q == 8 && countitem(PiberriesInfusion) >= 5, l("I have your package.")),
+ rif(.@q >= 10, l("I cleaned up the hill.")),
+ rif(.@q >= 10, l("How many Fluffies did I kill on the hill?")),
+ rif(.@q >= 1, l("Who is Don?")),
+ rif(.@q >= 5, l("Where is the light armor shop?")),
+ rif(.@q >= 7, l("Where is the market?")),
+ rif(.@q >= 10, l("Where is the hill?")),
+ rif(.@q >= 1, l("What is this \"legion\"?")),
+ l("I wish I could remember something..."),
+ rif(.@q != 0, l("Nothing."));
+
+ switch (@menu)
+ {
+ case 1:
+ enora_first_quest;
+ break;
+ case 2:
+ enora_quest_complete;
+ break;
+ case 3:
+ enora_paid_potions;
+ break;
+ case 4:
+ enora_hill_cleaned;
+ break;
+ case 5:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You killed @@ Fluffies.", getq2(ArtisQuests_Enora));
+ if (getq2(ArtisQuests_Enora) > 8)
+ {
+ mesq l("If you continue there will be none left!");
+ next;
+ }
+ break;
+ case 6:
+ enora_don;
+ case 7:
+ enora_light_armor;
+ break;
+ case 8:
+ enora_market;
+ break;
+ case 9:
+ enora_hill;
+ break;
+ case 10:
+ enora_legion;
+ break;
+ case 11:
+ enora_memories;
+ break;
+ case 12:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Please come back anytime!");
+ }
+ } while (@menu != 12);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 5;
+ .maxLevel = 20;
+ end;
+}
+
+function script EnoraKills {
+ if (getq(ArtisQuests_Enora) == 10
+ && killedrid == Fluffy
+ && strcharinfo(PC_MAP) == "001-1"
+ && getq2(ArtisQuests_Enora) < 10)
+ {
+ setq(ArtisQuests_Enora, 10, getq2(ArtisQuests_Enora) + 1);
+ }
+ return;
+}
+
diff --git a/npc/001-1/eugene.txt b/npc/001-1/eugene.txt
new file mode 100644
index 00000000..4f1e25fd
--- /dev/null
+++ b/npc/001-1/eugene.txt
@@ -0,0 +1,82 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// Fishman NPC
+// Quest variable:
+// ArtisQuests_Fishman
+// Quest stages:
+// 0 - not started
+// 1 - Eugene asked for items
+// 2 - completed
+
+001-1,113,120,0 script Eugene NPC_EUGENE,{
+
+ .BaitID = SmallTentacles;
+ .BaitCount = 10;
+
+ narrator S_LAST_NEXT,
+ l("You see a raijin boy, sitting on the edge of the dock."),
+ l("He's holding a fishing rod, while gazing out at the sea.");
+
+ .@q = getq(ArtisQuests_Fishman);
+ if (.@q == 1) goto L_CheckItems;
+ if (.@q == 2) goto L_QuestDone;
+
+ speech S_LAST_BLANK_LINE,
+ l("Ahoi."),
+ l("Hey, check out my brand new fishing rod. I bought it just today."),
+ l("I was so excited, I wanted to try it as soon as possible."),
+ l("So in a hurry, I forgot to take enough bait for fishing."),
+ l("Be a friend and bring me @@ @@.", .BaitCount, getitemlink(.BaitID));
+
+ switch (select(l("I'll be back in no time."),
+ l("Sorry, I'm doing other things at the moment.")))
+ {
+ case 1:
+ setq ArtisQuests_Fishman, 1;
+ speech S_FIRST_BLANK_LINE,
+ l("Thank you. I'll wait here.");
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("But I'm almost out of @@...", getitemlink(.BaitID));
+ close;
+ }
+
+L_CheckItems:
+ if (countitem(.BaitID) < .BaitCount)
+ {
+ speech
+ l("Sorry, but you don't have what I need."),
+ l("I need @@ @@.", .BaitCount, getitemlink(.BaitID));
+ close;
+ }
+
+ speech
+ l("That's exactly what I needed!"),
+ l("To thank you, accept my old fishing rod."),
+ l("It's not as good as my new one, but still very useful."),
+ l("Just look at that water! There's a whole bunch of fish down there."),
+ l("Oh, and you will need this book too, it will help you learn the basics of fishing."),
+ l("You might even get lucky, and get a @@.", getitemlink(GrassCarp)),
+ l("Have a good time fishing!");
+
+ delitem .BaitID, .BaitCount;
+ getitembound FishingRod, 1, IBT_ACCOUNT;
+ getitem FishingGuideVolI, 1;
+ setq ArtisQuests_Fishman, 2;
+ close;
+
+L_QuestDone:
+ // Idea for future: Eugene telling fishman jokes.
+ speech
+ l("Ahoy, @@!", strcharinfo(0)),
+ l("Are the fish biting today?");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/fexil.txt b/npc/001-1/fexil.txt
new file mode 100644
index 00000000..1122f051
--- /dev/null
+++ b/npc/001-1/fexil.txt
@@ -0,0 +1,143 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Newbie merchant.
+// Variables:
+// ArtisQuests_Fexil
+// Quest states:
+// 0 -- not started
+// 1 -- Lloyd warned about the quest
+// 2 -- Fexil explain what he needs
+// 3 -- Fexil buy every fur that the pc bring to him
+
+001-1,47,134,0 script Fexil#001-1 NPC_ELVEN_MAN_TRADER,{
+
+ function fexil_quest {
+ speech S_LAST_NEXT,
+ l("You know, the life of the merchant is hard. I really hope that Artis and the Merchant Guild will help me to succeed."),
+ l("Maybe you too you could help me?"),
+ l("I want to be the first merchant of this square to sell clothes made from @@s!", getitemlink(FluffyFur)),
+ l("I will buy all of the fur that you will bring me at a good price, let's say, 15 E piece."),
+ l("Do we have a deal?");
+
+ switch (select(l("Ok."), l("I don't want to be part of this joke.")))
+ {
+ case 1:
+ setq ArtisQuests_Fexil, 3;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Awesome! I will wait for you here.");
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh... Ok, I will be around here if you change your mind.");
+ break;
+ }
+ return;
+ }
+
+ mesn;
+ mesq l("Greetings traveler.");
+ next;
+ mesq l("I have some clothes and other things for you at a fine price!");
+ next;
+ mesq l("What I sell comes from every corner of Gasaron.");
+ next;
+ mesq l("Interested?");
+ next;
+
+ if (getq(ArtisQuests_Fexil) == 1)
+ {
+ select(l("I have your pass from the Merchant Guild."));
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh! You saved me, I was too afraid to unpack my stuff without this pass."),
+ l("Hey, I remember you, we were on the same boat, you are the castaway.");
+
+ switch (select(l("Yes I am."),
+ l("You're confusing me with someone else.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh sure I remember you."),
+ l("The travel was fine for you? It was terrible for me, I was sea-sick.");
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ah, I didn't have much sleep, it's possible.");
+ break;
+ }
+ setq ArtisQuests_Fexil, 2;
+ fexil_quest;
+
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ .@fexil = getq(ArtisQuests_Fexil);
+
+ select
+ l("OK, let's trade."),
+ rif(.@fexil == 2, l("Do you still need help?")),
+ rif(.@fexil > 2 && countitem(FluffyFur) > 0, l("I have some fur for you.")),
+ l("No. Sorry.");
+
+ switch (@menu)
+ {
+ case 1:
+ closeclientdialog;
+ shop "Bag#001-1";
+ close;
+
+ case 2:
+ mes "";
+ fexil_quest;
+ break;
+
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Awesome. How many of those do you want to give me?");
+
+ do
+ {
+ input .@amount;
+ if (.@amount < 1)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Please enter a valid amount.");
+ continue;
+ }
+ if (.@amount > countitem(FluffyFur))
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You don't have enough @@s on you.", getitemlink(FluffyFur));
+ continue;
+ }
+
+ break;
+ } while (1);
+
+ .@price = 15 * .@amount;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Deal, I offer you @@ E!", .@price);
+
+ delitem FluffyFur, .@amount;
+ Zeny += .@price;
+
+ break;
+
+ case 4:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh... Well, I just started to trade... Thus my technique may not be the best."),
+ l("Anyway, if you ever feel interested, just check my bag!");
+ break;
+ }
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/flags.txt b/npc/001-1/flags.txt
new file mode 100644
index 00000000..5e70c25a
--- /dev/null
+++ b/npc/001-1/flags.txt
@@ -0,0 +1,17 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// The flags supposed to mark Rowboat unmounting spots in Artis
+// THIS IS A PLACEHOLDER!
+
+001-1,200,63,0 script Flag#1 NPC_FLAG_L,{
+ OnTouch:
+ narrator
+ l("You see a suspicious greenish flag. It reminds you of something you seem to have forgotten.");
+ close;
+}
+
+001-1,27,101,0 duplicate(Flag#1) Flag#2 NPC_FLAG_R
+001-1,68,139,0 duplicate(Flag#1) Flag#3 NPC_FLAG_R
diff --git a/npc/001-1/flyingpiou.txt b/npc/001-1/flyingpiou.txt
new file mode 100644
index 00000000..ea48f4dc
--- /dev/null
+++ b/npc/001-1/flyingpiou.txt
@@ -0,0 +1,160 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Description:
+// Pious flying around town
+// Variables:
+// none
+
+function script ArtisFlyingPiouLogic {
+ .@tick = gettimetick(1);
+ .@LastTimeTouched = getvariableofnpc(.LastTimeTouched, strnpcinfo(3));
+ if (.@tick > .@LastTimeTouched + 300)
+ {
+ .speed = 200;
+ set getvariableofnpc(.LastPlayerTouched, strnpcinfo(3)), -1;
+ }
+ .@rnd = rand(5) - 3;
+ if (.@rnd > 0)
+ return execmovecmd("wait " + .@rnd);
+ return 0;
+}
+
+001-1,53,117,0 script #FlyingPiou1 NPC_FLYING_PIOU,{
+
+ function TryCatchPiou {
+ .@agi = readparam(bAgi);
+ @ArtisQuests_CatchPiouTries += 1;
+ getmapxy(.@map$, .@x1, .@y1, 1);
+ getmapxy(.@map$, .@x2, .@y2, 0);
+ .@distance = distance(.@x1, .@y1, .@x2, .@y2);
+ .@chance = max(ArtisQuests_CatchPiou_Difficulcy,
+ 20 + .@distance * 5 - .@agi/10 -
+ @ArtisQuests_CatchPiouTries);
+ return rand(.@chance);
+ }
+
+ .@charid = getcharid(0);
+ if (.LastPlayerTouched <= 0)
+ {
+ .LastPlayerTouched = .@charid;
+ @ArtisQuests_CatchPiouTries = 0;
+ }
+ else if (.LastPlayerTouched != .@charid)
+ {
+ message strcharinfo(0), l("Hm, it seems another player is trying to catch the piou, I shouldn't interfere.");
+ end;
+ }
+
+ .@q = getq(ArtisQuests_CatchPiou);
+ if (.@q != 1)
+ {
+ mesn "Narrator";
+ mesc(l("You scare the piou, but let it go."), 9);
+ close;
+ }
+
+ .@tick = gettimetick(1);
+ if (.@tick < .LastTimeTouched + min(4, ArtisQuests_CatchPiou_Difficulcy
+ + @ArtisQuests_CatchPiouTries / 3))
+ {
+ message strcharinfo(0), l("Dang, I scared it! More patience, @@, more patience.", strcharinfo(0));
+ .LastTimeTouched = .@tick;
+ specialeffect(33, SELF);
+ end;
+ }
+
+ .LastTimeTouched = .@tick;
+
+ .@rnd = TryCatchPiou();
+ if (!.@rnd)
+ {
+ npcstop;
+ stopnpctimer;
+ getmapxy(.@map$, .@x, .@y, 1);
+ npcwalkto .@x, .@y;
+ .@trader$ = "Salem#001-1";
+ mesn "Narrator";
+ mesc(l("You caught the piou, but it's trying to escape from you. You'd better hurry back to Salem."), 9);
+ set getvariableofnpc(.LastPiouHunter$, .@trader$), strcharinfo(0);
+ set getvariableofnpc(.PiouEscapedMessage$, .@trader$), l("Oh no, the piou escaped!");
+ set getvariableofnpc(.LastPiouHunterID, .@trader$), .@charid;
+ set getvariableofnpc(.PiouCaught, .@trader$), 1;
+ donpcevent .@trader$ + "::OnPiouFlee";
+ specialeffect(26, SELF);
+ close2;
+ disablenpc strnpcinfo(3);
+ close;
+ }
+ else
+ {
+ setarray .RandomFailureMessages$[0], l("So close!"), l("It escaped!"), l("Almost got it!"), l("Oh, the little...");
+ .@r = rand(getarraysize(.RandomFailureMessages$));
+ message strcharinfo(0), .RandomFailureMessages$[.@r];
+ .speed = max(140, 200 - 10 * (@ArtisQuests_CatchPiouTries +
+ ArtisQuests_CatchPiou_Difficulcy));
+ specialeffect(33, SELF);
+ }
+ end;
+
+OnHour00:
+ .LastTimeTouched = 0;
+ end;
+
+OnTimer1000:
+ dographmovestep;
+
+OnInit:
+ .distance = 5;
+ .walkmask = WALK_WATER;
+ // .debug = 1;
+
+ initmovegraph "market_start", 53, 117,
+ "fountain", 79, 75, 102, 91,
+ "river_bank_1", 107, 94, 117, 102,
+ "river_bank_2", 117, 110,
+ "chelios_right", 100, 112, 113, 118,
+ "chelios_left", 80, 95, 93, 111,
+ "market_right", 74, 114, 83, 121,
+ "market_center", 50, 113, 66, 121,
+ "market_left", 36, 120, 42, 128,
+ "batiment_inside", 48, 138, 65, 106,
+ "batiment_behind", 33, 90, 41, 103,
+ "library_front", 42, 82, 63, 90,
+ "taree_yard", 69, 82,
+ "taree_behind", 61, 62, 76, 71,
+ "townhall_behind", 73, 40, 93, 55,
+ "townhall_right", 99, 55, 106, 60,
+ "inn_behind", 107, 63, 123, 76
+ ;
+
+ setmovegraphcmd "fountain", "river_bank_1", 1, "call ArtisFlyingPiouLogic",
+ "river_bank_1", "river_bank_2", 1, "call ArtisFlyingPiouLogic",
+ "river_bank_2", "chelios_right", 2, "call ArtisFlyingPiouLogic",
+ "chelios_right", "chelios_left", 1, "call ArtisFlyingPiouLogic",
+ "chelios_left", "fountain", 1, "wait 1; call ArtisFlyingPiouLogic",
+ "chelios_left", "market_right", 1, "call ArtisFlyingPiouLogic",
+ "chelios_right", "market_right", 1, "call ArtisFlyingPiouLogic",
+ "market_right", "market_center", 1, "call ArtisFlyingPiouLogic",
+ "market_center", "batiment_inside",1, "call ArtisFlyingPiouLogic",
+ "batiment_inside","library_front", 1, "call ArtisFlyingPiouLogic",
+ "library_front", "taree_yard", 1, "call ArtisFlyingPiouLogic",
+ "library_front", "taree_behind", 1, "call ArtisFlyingPiouLogic",
+ "library_front", "batiment_behind",1, "call ArtisFlyingPiouLogic",
+ "batiment_behind","market_left", 1, "wait 3; call ArtisFlyingPiouLogic",
+ "market_left", "market_center", 1, "call ArtisFlyingPiouLogic",
+ "taree_yard", "fountain", 1, "call ArtisFlyingPiouLogic",
+ "taree_behind", "townhall_behind",1, "call ArtisFlyingPiouLogic",
+ "townhall_behind","townhall_right", 1, "call ArtisFlyingPiouLogic",
+ "townhall_right", "inn_behind", 1, "call ArtisFlyingPiouLogic",
+ "inn_behind", "fountain", 1, "wait 2; call ArtisFlyingPiouLogic",
+ "inn_behind", "river_bank_1", 1, "call ArtisFlyingPiouLogic",
+ "market_start", "batiment_inside",1, "call ArtisFlyingPiouLogic"
+ ;
+
+ firstmove "speed 200", "market_start";
+ initnpctimer;
+
+ .LastPlayerTouched = -1;
+ end;
+}
diff --git a/npc/001-1/harbours.txt b/npc/001-1/harbours.txt
new file mode 100644
index 00000000..f1db3fce
--- /dev/null
+++ b/npc/001-1/harbours.txt
@@ -0,0 +1,84 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Harbour animated tiles.
+// Animation:
+// Length: 1680
+// Values:
+// 2 Hook moving down.
+// 4 Hook moving up.
+// 6 Hook down.
+// 8 Hook up.
+
+001-1,183,85,0 script #Harbour1 NPC_HARBOUR_WHEEL_BOX,{
+ harbourClic;
+
+OnTimer1670:
+ harbourTimer;
+
+OnInit:
+ .distance = 1;
+ .alwaysVisible = true;
+ end;
+}
+
+001-1,183,89,0 script #Harbour2 NPC_HARBOUR_WHEEL,{
+ harbourClic;
+
+OnTimer1670:
+ harbourTimer;
+
+OnInit:
+ .distance = 1;
+ .alwaysVisible = true;
+ end;
+}
+
+001-1,198,115,0 script #Harbour3 NPC_HARBOUR_WHEEL_BOX,{
+ harbourClic;
+
+OnTimer1670:
+ harbourTimer;
+
+OnInit:
+ .distance = 1;
+ .alwaysVisible = true;
+ end;
+}
+
+001-1,175,119,0 script #Harbour4 NPC_HARBOUR_WHEEL_BOX,{
+ harbourClic;
+
+OnTimer1670:
+ harbourTimer;
+
+OnInit:
+ .distance = 1;
+ .alwaysVisible = true;
+ end;
+}
+
+001-1,198,92,0 script #Harbour5 NPC_HARBOUR_WHEEL_BOX,{
+ harbourClic;
+
+OnTimer1670:
+ harbourTimer;
+
+OnInit:
+ .distance = 1;
+ .alwaysVisible = true;
+ end;
+}
+
+001-1,151,117,0 script #Harbour6 NPC_HARBOUR_WHEEL,{
+ harbourClic;
+
+OnTimer1670:
+ harbourTimer;
+
+OnInit:
+ .distance = 1;
+ .alwaysVisible = true;
+ end;
+}
diff --git a/npc/001-1/juscare.txt b/npc/001-1/juscare.txt
new file mode 100644
index 00000000..b0d6a98e
--- /dev/null
+++ b/npc/001-1/juscare.txt
@@ -0,0 +1,92 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// Juscare, walking NPC of the Legion of Aemil on the right part of the Agora of Artis.
+
+001-1,118,92,0 script Juscare#001-1 NPC_HUMAN_MALE_LEGION_ARTIS,{
+
+ function shouldTurn {
+ .@tree = findmovegraphlabel("inn_tree");
+ .@table = findmovegraphlabel("inter_inn_fav_table");
+ if (.movepos == .@tree || .movepos == .@table)
+ return 0;
+ return 1;
+ }
+
+ function localClose {
+ if (@Juscar_old_dir > 0)
+ .dir = @Juscar_old_dir;
+ npc_resumemove;
+ close;
+ }
+
+ npc_pausemove;
+ @Juscar_old_dir = -1;
+ if (shouldTurn())
+ {
+ getmapxy(.@map$, .@cx, .@cy, 0);
+ @Juscar_old_dir = .dir;
+ npc_turntoxy(.@cx, .@cy);
+ }
+
+ villagertalk();
+
+ localClose;
+
+OnTimer1000:
+ dographmovestep;
+
+OnInit:
+ .distance = 4;
+ // .debug = 1;
+ initmovegraph
+ "inn_front", 112, 90, 119, 93,
+ "inn_tree", 108, 82,
+ "fountain", 87, 85, 91, 86,
+ "chelios", 93, 109,
+ "chelios_road", 89, 107,
+ "chelios", 93, 109,
+ "to_market", 76, 119,
+ "market", 60, 115, 65, 121,
+ "fishing_spot", 109, 127,
+ "river_bank", 113, 105,
+ "eugene", 112, 115,
+ "inn_door", 118, 89,
+ "inn_doorstep", 118, 88,
+ "inter_inn_doorstep", 29, 43,
+ "inter_inn_2tables", 38, 31,
+ "inter_inn_fav_table", 51, 33;
+
+ // this is not very obvious stuff
+ setmovegraphcmd
+ "inn_front", "inn_door", 1, 0x1, "flags_0 2; dir 4; call open_door #001-1_118_88",
+ "inn_front", "inn_tree", 2, "dir 2; wait 1; sit; wait 1; emote 106; wait 20; stand; wait 1",
+ "inn_front", "river_bank",1, "flags_0 8; flags_1 4",
+ "river_bank", "eugene", 1, 0x4, "moveon",
+ "eugene", "fishing_spot", 1, 0x4, "wait 7",
+ "fishing_spot", "chelios", 1, 0x4, "dir 6; wait 1; emote 103; wait 10",
+ "inn_tree", "inn_door", 1, "flags_1 1; flags_0 2; dir 4; call open_door #001-1_118_88",
+ "inn_tree", "fountain", 2, "dir 4; wait 1; emote 122; wait 10; dir 0; wait 1",
+ "fountain", "chelios_road", "moveon",
+ "chelios_road", "chelios", "dir 6; wait 1; emote 103; wait 7",
+ "chelios", "eugene", "flags_1 28; flags_0 4",
+ "chelios", "to_market", 2, 0x20, "flags_1 20; flags_0 10",
+ "to_market", "market", 1, 0x20, "flags_1 10; flags_0 20; wait 20",
+ "market", "to_market", "moveon",
+ "to_market", "chelios", 1, 0x10, "flags_0 10; dir 6; wait 3",
+ "fishing_spot", "eugene", 1, 0x8, "moveon",
+ "eugene", "river_bank",1, 0x8, "moveon",
+ "river_bank", "inn_front", 1, 0x8, "dir 0; wait 5",
+ "inn_door", "inn_doorstep",1, 0x1, "warp 001-2-28 inter_inn_doorstep; call close_door #001-1_118_88",
+ "inter_inn_doorstep", "inter_inn_2tables", 1, 0x1, "moveon",
+ "inter_inn_2tables", "inter_inn_fav_table", 1, 0x1, "flags_1 2; flags_0 1; dir 6; wait 1; sit; wait 15; stand; wait 1",
+ "inter_inn_fav_table", "inter_inn_2tables", 1, 0x2, "moveon",
+ "inter_inn_2tables", "inter_inn_doorstep", 1, 0x2, "call open_door #001-1_118_88; warp 001-1 inn_doorstep",
+ "inn_doorstep", "inn_door", 1, 0x2, "call close_door #001-1_118_88",
+ "inn_door", "inn_front", 1, 0x2, "flags_1 1; flags_0 2; wait 10";
+
+ firstmove "wait 4", "inn_front";
+ initnpctimer;
+}
diff --git a/npc/001-1/katja.txt b/npc/001-1/katja.txt
new file mode 100644
index 00000000..3a3008cb
--- /dev/null
+++ b/npc/001-1/katja.txt
@@ -0,0 +1,128 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// Little girl playing around the hill on top of the port.
+// She wants you to find her brother.
+// Variables:
+// ArtisQuests_LazyBrother = 19 -- quest var
+// LazyBrother_TreesLeft = 15 -- how many trees left to search
+// LazyBrother_TreeSearched[15] -- whether given tree was searched
+// LazyBrother_TreeWithBrother -- the number of tree where he's hiding
+// Quest states:
+// 0 - quest not started
+// 1 - Katja asked help, searching the trees
+// 2 - Bobo is found, "bad" ending
+// 3 - player decided to tell Katja where her brother is
+// 4 - "good" ending, player helped Katja
+
+001-1,164,44,0 script Katja#001-1 NPC_RAIJIN_GIRL,{
+
+ function QuestReminder {
+ setcam 5920, 960;
+ mesq l("Remember, you have to find my brother on the hill east of here.");
+ next;
+ mesq l("He is probably hiding up one of the trees. Go close to each tree and look up, otherwise you won't notice him.");
+ next;
+ restorecam;
+ }
+
+ .@q = getq(ArtisQuests_LazyBrother);
+ mesn;
+ mesq l("Hey");
+ next;
+ switch(.@q)
+ {
+ case 0:
+ mesq l("You look nice, do you want to help me?");
+ break;
+ case 1:
+ mesq l("Hi, how is it going?");
+ next;
+ select l("Remind me, what should I do?");
+ mes "";
+ mesn;
+ QuestReminder;
+ close;
+ case 2:
+ mesq l("I still didn't find my brother...");
+ close;
+ case 3:
+ mesq l("Did you find my brother?");
+ next;
+ select(l("Yes, and he promised to be home soon."));
+ mes "";
+ mesn;
+ mesq l("Oh thank you so much!");
+ next;
+ mesq l("Please take this @@ for your help.", getitemlink(Aquada)); // Need a different reward.
+ setq ArtisQuests_LazyBrother, 4;
+ getitem Aquada, 1;
+ getexp 500, 0;
+ close;
+ case 4:
+ mesq l("Thank you again for your help!");
+ close;
+ }
+ next;
+
+ switch (select(l("Of course!"),
+ l("What kind of help do you need?"),
+ l("I don't have much time right now.")))
+ {
+ case 1:
+ mes "";
+ mesn;
+ mesq l("Great!");
+ emotion E_JOY;
+ next;
+ break;
+ case 2:
+ mes "";
+ mesn;
+ break;
+ case 3:
+ mes "";
+ mesn;
+ mesq l("Okay, I'll be here, if you change your mind.");
+ emotion E_SAD;
+ close;
+ }
+
+L_Story:
+ mesq l("Mommy sent me to find my brother Bobo.");
+ next;
+ mesq l("He said he is going to climb the highest hill in Artis, which is not far from here.");
+ next;
+ mesq l("Our mommy doesn't allow us to go there, because it's dangerous. But he doesn't listen!");
+ next;
+ mesq l("Can you please go there and find him? He is probably hiding in one of those trees, like always.");
+ next;
+ mesq l("Because of the dense foliage, you need to go up close to the trees so you don't miss him.");
+ next;
+
+ switch (select(l("I will find him, don't worry!"),
+ l("Highest hill in Artis you say? Sounds dangerous, I might fall off.")))
+ {
+ case 1:
+ mes "";
+ mesn;
+ mesq l("Thank you!");
+ mes "";
+ QuestReminder;
+ setq ArtisQuests_LazyBrother, 1;
+ LazyBrother_TreesLeft = 15;
+ close;
+ case 2:
+ mes "";
+ mesn;
+ mesq l("Aw, what will I do now?");
+ close;
+ }
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/001-1/koga.txt b/npc/001-1/koga.txt
new file mode 100644
index 00000000..794909f1
--- /dev/null
+++ b/npc/001-1/koga.txt
@@ -0,0 +1,45 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// The Koga in Artis, only accessable via Rowboat.
+// THIS IS A PLACEHOLDER!
+
+/*001-1,225,59,0 script Koga#001-1 NPC_LA_MARINE,{
+ .@q=getq(General_Narrator);
+ speech
+ l("Ah, whom did you bring here?"),
+ l("Isn't that the one Nard found on a raft in the sea, with the sign of the Legion on it?");
+ next;
+ mesc l("Travel to woodlands?");
+ if (askyesno() == ASK_YES)
+ {
+ speech
+ l("I hope they know what they are doing. So, come on board. I am looking forward to go back to Woodland, haven't been there for a while.");
+ next;
+ closeclientdialog;
+ setpcblock(PCBLOCK_MOVE, false);
+ setmount 0;
+ if (.@q == 1) {
+ warp "000-0-1", 26, 28;
+ close;
+ }
+ warp "008-1-1", 33, 63;
+ dispbottom l("After a tiring, yet fast, travel by Koga, you arrive at @@.", l("Woodlands"));
+ }
+ else
+ {
+ // Return you to beach
+ setpcblock(PCBLOCK_MOVE, false);
+ setmount 0;
+ slide 200, 62;
+ }
+
+ close;
+
+OnInit:
+ .distance = 6;
+ //.alwaysVisible = true;
+ end;
+}*/
+
diff --git a/npc/001-1/lucas.txt b/npc/001-1/lucas.txt
new file mode 100644
index 00000000..558889d2
--- /dev/null
+++ b/npc/001-1/lucas.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Legion member.
+
+001-1,59,44,0 script Lucas#001-1 NPC_LUCAS,{
+
+ villagertalk();
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-1/manhole.txt b/npc/001-1/manhole.txt
new file mode 100644
index 00000000..086f9070
--- /dev/null
+++ b/npc/001-1/manhole.txt
@@ -0,0 +1,88 @@
+// Evol scripts.
+// Author:
+// Jesusalva
+// Reid
+// Description:
+// A manhole near Mona's house.
+// Variable:
+// ArtisQuests_MonaDad
+// Quest states:
+// 0 - Quest not started
+// 1 - Mona explained that her dad was missing
+
+001-1,152,52,0 script #manhole1-001-1 NPC_NO_SPRITE,{
+
+ .@i=manhole_interact("001-3-0");
+ closeclientdialog();
+ if (.@i == -1) {
+ slide_or_warp("001-3-0", 152, 56);
+ } else if (.@i == TrainingArrow || .@i == WoodenBow) {
+ npctalk3 l("(You hear a faint sound in distance, but can't say what sound it was.)");
+ }
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,196,35,0 script #manhole2-001-1 NPC_NO_SPRITE,{
+
+ .@i=manhole_interact("001-3-0");
+ closeclientdialog();
+ if (.@i == -1) {
+ slide_or_warp("001-3-0", 196, 36);
+ } else if (.@i == TrainingArrow || .@i == WoodenBow) {
+ npctalk3 l("???: Hey! Is someone there? Please, help, it's so dark down here!");
+ }
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,146,123,0 script #manhole3-001-1 NPC_NO_SPRITE,{
+
+ .@i=manhole_interact("001-3-0");
+ closeclientdialog();
+ if (.@i == -1) {
+ // Not a fan of calling strong players as weak, so take STR in account
+ // If you have enough STR, you get an Easter Egg about the engine :)
+ if (readparam(bStr) < 50) {
+ mesc l("The lid is sealed shut, and you are too weak to open it.");
+ } else {
+ mesc l("Even with your Hercules strength, this lid is hopelessly struck.");
+ }
+ } else if (.@i == TrainingArrow || .@i == WoodenBow) {
+ // This is the wrong lid for Mundane Quest
+ npctalk3 l("...");
+ }
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+// This lid can only be used to leave
+001-1,86,131,0 script #manhole4-001-1 NPC_NO_SPRITE,{
+
+ .@i=manhole_interact("001-3-0");
+ closeclientdialog();
+ if (.@i == -1) {
+ mesc l("Strangely enough, this lid can only be open from inside.");
+ } else if (.@i == TrainingArrow || .@i == WoodenBow) {
+ // This is the wrong lid for Mundane Quest
+ npctalk3 l("...");
+ }
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+// To quickly create more sewer mouths we can use:
+//001-1,86,131,0 duplicate(#manhole3-001-1) #manhole4-001-1 NPC_NO_SPRITE
+
diff --git a/npc/001-1/mapflags.txt b/npc/001-1/mapflags.txt
new file mode 100644
index 00000000..3e529501
--- /dev/null
+++ b/npc/001-1/mapflags.txt
@@ -0,0 +1 @@
+001-1 mapflag town
diff --git a/npc/001-1/marine.txt b/npc/001-1/marine.txt
new file mode 100644
index 00000000..b9cd93f9
--- /dev/null
+++ b/npc/001-1/marine.txt
@@ -0,0 +1,17 @@
+// Moubootaur Legends scripts.
+// Authors:
+// Jesusalva
+// Description:
+// This script controls access to Ships, fixing variables.
+
+// Use NPC_LA_MARINE if needed
+001-1,204,85,0 script Gema IV#A NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ EnterTown("Artis");
+
+ warp "marine@"+LOCATION$, 42, 26;
+ closedialog;
+ close;
+}
diff --git a/npc/001-1/merlin.txt b/npc/001-1/merlin.txt
new file mode 100644
index 00000000..a96e404d
--- /dev/null
+++ b/npc/001-1/merlin.txt
@@ -0,0 +1,24 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Fishmonger NPC
+
+001-1,73,128,0 script Merlin NPC_MERLIN,2,2,{
+
+OnTouch:
+ switch(rand(6))
+ {
+ case 0: npctalkonce(l("Fish, come and see my fish!")); break;
+ case 1: npctalkonce(l("They are fresh, they are good!")); break;
+ case 2: npctalkonce(l("Fresh from the sea and cheap!")); break;
+ case 3: npctalkonce(l("Come, come and see!")); break;
+ case 4: npctalkonce(l("They are fresh!")); break;
+ default: npctalkonce(l("Fish is good for the brain!"));
+ }
+ end;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/mouboo.txt b/npc/001-1/mouboo.txt
new file mode 100644
index 00000000..bdc4d517
--- /dev/null
+++ b/npc/001-1/mouboo.txt
@@ -0,0 +1,61 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Mouboo on Taree's fence.
+
+001-1,67,79,4 script Mouboo#Artis0 NPC_MOUBOO,{
+
+ moubootalk();
+ close;
+
+OnTimer2000:
+ moubootimer;
+
+OnInit:
+ .distance = 2;
+ .speed = 600;
+ mouboograph;
+}
+
+001-1,67,80,4 script Mouboo#Artis1 NPC_MOUBOO,{
+
+ moubootalk();
+ close;
+
+OnTimer2000:
+ moubootimer;
+
+OnInit:
+ .distance = 2;
+ .speed = 600;
+ mouboograph;
+}
+
+001-1,67,81,4 script Mouboo#Artis2 NPC_MOUBOO,{
+
+ moubootalk();
+ close;
+
+OnTimer2000:
+ moubootimer;
+
+OnInit:
+ .distance = 2;
+ .speed = 600;
+ mouboograph;
+}
+
+001-1,67,82,4 script Mouboo#Artis3 NPC_MOUBOO,{
+
+ moubootalk();
+ close;
+
+OnTimer2000:
+ moubootimer;
+
+OnInit:
+ .distance = 2;
+ .speed = 600;
+ mouboograph;
+}
diff --git a/npc/001-1/nalkri.txt b/npc/001-1/nalkri.txt
new file mode 100644
index 00000000..e155a8a8
--- /dev/null
+++ b/npc/001-1/nalkri.txt
@@ -0,0 +1,59 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Nalkri, walking NPC of the Legion of Aemil on the west part of Artis.
+
+001-1,35,84,0 script Nalkri#001-1 NPC_DEMON_MALE_LEGION_ARTIS,{
+ npctalk3 l("Stay clear.");
+ close;
+
+OnTimer1000:
+ domovestep;
+
+OnInit:
+ initpath "move", 56, 84,
+ "move", 60, 93,
+ "move", 68, 98,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "move", 68, 100,
+ "dir", RIGHT, 0,
+ "wait", 1, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "dir", UP, 0,
+ "move", 67, 98,
+ "dir", RIGHT, 0,
+ "wait", 2, 0,
+ "move", 51, 101,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", RIGHT, 0,
+ "wait", 1, 0,
+ "dir", UP, 0,
+ "move", 48, 100,
+ "dir", RIGHT, 0,
+ "wait", 1, 0,
+ "dir", DOWN, 0,
+ "wait", 1, 0,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "dir", RIGHT, 0,
+ "move", 55, 96,
+ "move", 43, 88,
+ "move", 35, 84,
+ "dir", LEFT, 0,
+ "wait", 1, 0,
+ "dir", DOWN, 0,
+ "wait", 4, 0,
+ "dir", RIGHT, 0,
+ "wait", 1, 0;
+
+ initialmove;
+ initnpctimer;
+}
diff --git a/npc/001-1/panels.txt b/npc/001-1/panels.txt
new file mode 100644
index 00000000..19d1fb11
--- /dev/null
+++ b/npc/001-1/panels.txt
@@ -0,0 +1,57 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Panels to give advice and some random information to players.
+
+001-1,180,25,0 script #ArtisPanel1 NPC_NO_SPRITE,{
+ narrator S_LAST_NEXT,
+ l("You step on something, a panel half overgrown by moss, it has writing on it...");
+
+ mesq l("Don't fall!");
+ next;
+ mesq l("You've reached the highest natural place of Artis, enjoy the view.");
+ next;
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
+001-1,95,51,0 script #ArtisPanel2 NPC_NO_SPRITE,{
+ narrator S_LAST_NEXT,
+ l("You step on something, a shaky and fragile panel with barely visible inscriptions on it...");
+
+ mesq l("Beware of falling stones from the cliff!");
+ next;
+ mesq l("The other part of this sign has been crushed by a rock.");
+ next;
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
+001-1,103,66,0 script #ArtisPanel3 NPC_NO_SPRITE,{
+ narrator S_LAST_NEXT,
+ l("You step on something, a panel with a bitten corner and clear inscriptions on it...");
+
+ mesq l("Warning! Dangerous fish, do not fall into the lake!");
+ next;
+ narrator S_LAST_NEXT,
+ l("Somebody tried to stroke the word \"fish\" and tried to replace it with \"sharkes\".");
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
diff --git a/npc/001-1/pious.txt b/npc/001-1/pious.txt
new file mode 100644
index 00000000..35e65048
--- /dev/null
+++ b/npc/001-1/pious.txt
@@ -0,0 +1,15 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Description:
+// Pious on Market
+// Variables:
+// none
+
+001-1,55,119,0 script #MarketPiou1 NPC_MARKET_PIOU,{
+ end;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-1/qonan.txt b/npc/001-1/qonan.txt
new file mode 100644
index 00000000..f00a2cf3
--- /dev/null
+++ b/npc/001-1/qonan.txt
@@ -0,0 +1,113 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// Sailor of Nard's La Johanne ship.
+// ArtisQuests_QOnan -- quest variable:
+// 0 - not started
+// 1 - Q'Onan asked to find Chest
+// 2 - Chest found, heading back to Q'Onan
+// 3 - Quest completed
+
+001-1,186,107,0 script Q'Onan#001-1 NPC_QONAN,{
+
+ .@q = getq(ArtisQuests_QOnan);
+ if (.@q == 1) goto L_QuestGiven;
+ if (.@q == 2) goto L_ItemFound;
+ if (.@q == 3) goto L_QuestDone;
+
+ speech S_LAST_BLANK_LINE,
+ l("We haven't met, right?"),
+ l("My name is Q'Onan, I'm a member of Nard's crew."),
+ l("I have a lot of work here, so I don't even have time to go to the town."),
+ l("Could you do a small favor for me?");
+
+ switch (select(l("Go on."), l("I don't have the time sorry.")))
+ {
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("No problem, see you next time.");
+ closeclientdialog;
+ close;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("Before I joined Nard, I used to be a thief."),
+ l("I'm not proud of it, but I had to steal money from others to keep on living."),
+ l("Anyway, the last time I stole something I was almost caught."),
+ l("I robbed a nobleman, took a chest full of coins."),
+ l("But my luck left me, because as soon as I left his house, the guards started chasing me."),
+ l("It was at night, so I could barely escape. I ran to Artis hill."),
+ l("I was afraid to get busted, so I decided to get rid of the evidence."),
+ l("I buried the chest somewhere on that hill. It was dark, so I don't remember where to dig exactly."),
+ l("I'm afraid to go there myself, but if you take the risk, you can have half of the loot."),
+ l("So, what do you say?");
+
+ select
+ l("I like money! Consider it done."),
+ l("Too risky, I might end up in jail. Do it yourself.");
+
+ switch(@menu)
+ {
+ case 1:
+ setq ArtisQuests_QOnan, 1;
+ getrandompoint(178,26,182,29);
+ npcdebug "Chest buriad at (" + .move__rand_x + "," + .move__rand_y + ")";
+ shovel_addquest("001-1", .move__rand_x, .move__rand_y, "QOnanFoundItem");
+ speech S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("Alright, you will need this shovel."),
+ l("You should check on the highest part of the cliff, I was hiding there."),
+ l("I hope to see you soon.");
+ getitem IronShovel, 1;
+ // For questlog
+ setq2 ArtisQuests_QOnan, .move__rand_x+any(-1,1);
+ setq3 ArtisQuests_QOnan, .move__rand_y+any(-1,1);
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("Come on, don't be a coward!"),
+ l("Anyway, let me know if you change your mind.");
+ close;
+ }
+
+L_QuestGiven:
+ speech S_LAST_NEXT, l("I asked you to do me a favor, did you forget?");
+ select l("What should I do, again?");
+ speech S_FIRST_BLANK_LINE,
+ l("Please find the small chest, buried somewhere on Artis hill."),
+ l("You should check on the highest part of the cliff, I was hiding there."),
+ l("Bring it to me, and you will get your reward.");
+ close;
+
+L_ItemFound:
+ speech
+ l("After all this time, it was still there!"),
+ l("We are very lucky, my friend."),
+ l("Let me open it with my key."),
+ l("Like I promised, here is your share."),
+ l("I can finally pay off my debts.");
+
+ Zeny += 1800;
+ setq ArtisQuests_QOnan, 3;
+ close;
+
+L_QuestDone:
+ speech l("Howdy, partner in crime?");
+ close;
+
+OnInit:
+ .distance = 2;
+ .debug = 1;
+ end;
+}
+
+function script QOnanFoundItem {
+ setq ArtisQuests_QOnan, 2, 0, 0;
+ // getitem SmallChest, 1;
+ narrator S_FIRST_BLANK_LINE,
+ l("You found a small chest, surprisingly heavy for it's size."),
+ l("It's probably full of coins, but no matter how hard you try to open it, you can't."),
+ l("Better take it back to Q'Onan.");
+ return;
+}
diff --git a/npc/001-1/qpid.txt b/npc/001-1/qpid.txt
new file mode 100644
index 00000000..5976c9cf
--- /dev/null
+++ b/npc/001-1/qpid.txt
@@ -0,0 +1,169 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Potion seller, she is part of the Enora's noob quests.
+
+001-1,65,116,0 script Q'Pid#001-1 NPC_QPID,{
+
+ function riddle_enigma {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ok fine, you have up to 3 tries, here is the riddle:"),
+ l("What is growing and shrinking at the same time?");
+ narrator S_LAST_NEXT,
+ l("You need to type the answer of this riddle in the NPC window."),
+ l("The answer is a single word, without conjugation."),
+ l("You can also answer in your native language or in English.");
+
+ do
+ {
+ input .@answer$;
+ .@i++;
+
+ if (riddlevalidation(.@answer$, "life", l("life")))
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh..."),
+ l("You seem more cultivated than you look.");
+
+ if (getq(ArtisQuests_Enora) == 7)
+ {
+ setq(ArtisQuests_Enora, 9);
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("Fine, take these potions, I will replenish them in the next couple hours anyway.");
+ }
+
+ break;
+ }
+ else if (.@i < 3)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Too bad, try again.");
+ }
+ else
+ {
+ if (getq(ArtisQuests_Enora) == 7)
+ {
+ setq(ArtisQuests_Enora, 8);
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You failed!"),
+ l("Ivan is the one you should look for now."),
+ l("He is in a small house between the dock's warehouse and the dojo."),
+ l("Follow the canal to the north-east and you will find it."),
+ l("And get out of here, I'm not a map!");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You failed!");
+ }
+
+ break;
+ }
+ } while (true);
+
+ return;
+ }
+
+ function enora_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("She wants? What if I don't want?"),
+ l("I'm not a pawn of the Legion, I don't have to obey you!"),
+ l("Oh and guess what! I'm almost out of potions anyway.");
+
+ switch (select(l("And where can I find these potions?"),
+ l("You bored me, see you later.")))
+ {
+ case 1:
+ break;
+ case 2:
+ return;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You don't seem to be from the Legion, let's do a game."),
+ l("If you find the correct answer, I will give you these potions..."),
+ l("But if you fail, you will have to get them from the alchemist."),
+ l("Deal?");
+
+ if (askyesno() == ASK_YES)
+ {
+ riddle_enigma;
+ }
+ return;
+ }
+
+ function alchemist_information {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Do? I don't do them."),
+ l("I'm sure that you already knew the answer, didn't you?"),
+ l("You tried to embarrass me, am I right?!"),
+ l("It's Ivan... I'm sure that he sent you to annoy me..."),
+ l("I'm just a merchant, I trade and make deals, yes \"excuse\" me if I'm not as skilled as that stupid alchemist."),
+ l("But rare are those that receive grants from the Legion itself. For anybody else only a hard work can pay your bills!");
+ emotion E_UPSET;
+
+ switch (select(l("Sorry I didn't mean to bother you."),
+ l("You are just sitting on the shadow of your store.")))
+ {
+ case 1:
+ mes "";
+ mesn;
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("You are honest, I like it.");
+ break;
+ }
+ mesq l("Is that all you had to say?");
+ next;
+
+ return;
+ }
+
+ speech S_LAST_NEXT,
+ l("What?");
+
+ do
+ {
+ .@enora = getq(ArtisQuests_Enora);
+
+ select
+ rif(.@enora == 7, l("Enora wants her potions.")),
+ menuaction(l("Trade")),
+ rif(.@enora > 7, l("What was your riddle?")),
+ l("How do you do your potions?"),
+ l("What are you reading?"),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ enora_quest;
+ break;
+ case 2:
+ closeclientdialog;
+ shop "Store#Potion001-1";
+ close;
+ case 3:
+ riddle_enigma;
+ break;
+ case 4:
+ alchemist_information;
+ break;
+ case 5:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It's a poem, about poems... Why are you asking that?"),
+ l("Because I am a Kralog I can't read such things? That's rubbish."),
+ l("I borrowed it from the library, you should try to cultivate yourself more instead of insinuate things about people you don't know!");
+ break;
+ }
+ } while (@menu != 6);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/001-1/rowboat.txt b/npc/001-1/rowboat.txt
new file mode 100644
index 00000000..ba07a1b0
--- /dev/null
+++ b/npc/001-1/rowboat.txt
@@ -0,0 +1,69 @@
+// Evol scripts.
+// Author:
+// Micksha, Toams
+// Description:
+// The rowboat, picking up the player on small beach in order to bring it to Koga.
+
+001-1,192,25,0 script #Rowboat NPC_ROWBOAT_STAND_WE,{
+ if (.caller != getcharid(3)) {
+ mesn;
+ mesq l("Oh, hello. I am just observing the whales.");
+ next;
+ mesn;
+ mesq l("Nobody told me anything about you, unfortunately.");
+ close;
+ }
+
+ speech S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh, hi."),
+ l("In case you don't have a commendatory letter from you-know-whom, I am just sitting here and observe the whales."),
+ l("Perhaps, and only perhaps, if you bring me the latter, I can bring you to a ship that will perhaps, and only perhaps, be able to bring you to Woodland."),
+ l("Do you have this commendatory letter?");
+ closeclientdialog();
+ if (askyesno() == ASK_YES) {
+ if (getq(General_Brotherhood) >= 2)
+ {
+ //slide 227, 62;
+ //slide 204, 62;
+ PC_DEST$="Argaes";
+ @timer_navio_running = 1;
+ addtimer 210000, "#MarineShip::OnEvent"; // This route is 30s slower
+ warp "marine-2", 40, 32;
+ dispbottom l("You're smuggled aboard the Legion expedition. ACT NATURALLY!");
+ .caller=0;
+ .clocks=gettimetick(2);
+ movenpc("#Rowboat", 192, 25);
+ //setmount 1;
+ }
+ else
+ {
+ npctalk3 l("You're lying, aren't you? I heard nothing from you-know-whom!");
+ }
+ close;
+ }
+
+OnMoveToBeach:
+ startnpctimer;
+ initialmove;
+end;
+
+OnTimer1000:
+ getmapxy(.@map$, .@cx, .@cy, 1);
+ if (.@cx == 192 && .@cy == 25) stopnpctimer;
+ else domovestep;
+
+OnInit:
+ .distance = 3;
+ .speed = 175;
+ .caller = 0;
+ .clocks = 0;
+
+ initpath "move", 202, 27,
+ "move", 213, 58,
+ "move", 203, 64,
+ "wait", 15, 0,
+ "move", 213, 58,
+ "move", 202, 27,
+ "move", 192, 25;
+ initnpctimer;
+}
diff --git a/npc/001-1/rowboathelper.txt b/npc/001-1/rowboathelper.txt
new file mode 100644
index 00000000..d7809bf0
--- /dev/null
+++ b/npc/001-1/rowboathelper.txt
@@ -0,0 +1,141 @@
+// Evol scripts.
+// Author:
+// Toams
+// Description:
+// helper scripts for rowboat usage
+// Notes:
+// Curious Hole bypass the cutscenes
+
+// calling the Rowboat
+001-1,200,60,0 script Curious Hole NPC_NO_SPRITE,{
+
+ .@q = getq(General_Narrator);
+
+ mesc l("You see a curious hole behind some rocks.");
+ next;
+ mesn strcharinfo(0);
+ mesq l("Hey, anyone there?");
+ next;
+ mesc l("...");
+ next;
+ if (.@q < 2)
+ {
+ mesc l("Altough you can't get rid of the feeling someone is listening on the other side, you don't get any replies.");
+ close;
+ }
+ else
+ {
+ narrator(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("Suddenly you remember the strange phrase Mona overheard Sophialla saying"),
+ l("Maybe you should try this phrase?"));
+ if (askyesno() == ASK_YES)
+ {
+ mesn strcharinfo(0);
+ mesc l("Sagratha is great.");
+ next;
+
+ if (getvariableofnpc(.caller, "#Rowboat")) {
+ // Can you use it, or is it in grace time?
+ if (getvariableofnpc(.clocks, "#Rowboat") > gettimetick(2)) {
+ mesn;
+ mesq l("Please be patient. Someone else is using the rowboat right now.");
+ close;
+ }
+ // Rowboat already there, so change owner
+ mesn;
+ mesq l("Hello, a rowboat is already on the beach. You can use it.");
+ set(getvariableofnpc(.caller, "#Rowboat"), getcharid(3));
+ set(getvariableofnpc(.clocks, "#Rowboat"), gettimetick(2)+15);
+ close;
+ }
+ // Rowboat is at hideout, send it to you
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Hello, a rowboat is on his way to the beach. Please wait for a while for it to arrive.");
+
+ set(getvariableofnpc(.caller, "#Rowboat"), getcharid(3));
+ set(getvariableofnpc(.clocks, "#Rowboat"), gettimetick(2)+30);
+ doevent("#Rowboat::OnMoveToBeach");
+ close;
+ }
+ else
+ close;
+ }
+
+OnInit:
+ .distance = 1;
+}
+
+// UNUSED
+//unmounting the rowboat at eastern beach
+001-1,202,62,0 script unmountrowboateast NPC_HIDDEN,1,1,{
+
+ function UnMount {
+ narrator(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("Do you want to leave the boat?"));
+ if (askyesno() == ASK_YES)
+ {
+ slide_or_warp("001-1", 199, 62);
+ setmount 0;
+ close;
+ }
+}
+
+OnTouch:
+ UnMount;
+ end;
+
+OnInit:
+ .distance = 1;
+}
+
+
+//unmounting the rowboat at southern beach
+001-1,68,143,0 script unmountrowboatsouth NPC_HIDDEN,1,1,{
+
+ function UnMount {
+ narrator(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("Do you want to leave the boat?"));
+ if (askyesno() == ASK_YES)
+ {
+ slide_or_warp("001-1", 68, 138);
+ setmount 0;
+ close;
+ }
+}
+
+OnTouch:
+ UnMount;
+ end;
+
+OnInit:
+ .distance = 1;
+}
+
+
+//unmounting the rowboat at western beach
+001-1,25,101,0 script unmountrowboatwest NPC_HIDDEN,1,1,{
+
+ function UnMount {
+ narrator(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("Do you want to leave the boat?"));
+ if (askyesno() == ASK_YES)
+ {
+ slide_or_warp("001-1", 27, 101);
+ setmount 0;
+ close;
+ }
+}
+
+OnTouch:
+ UnMount;
+ end;
+
+OnInit:
+ .distance = 1;
+}
+
+function script ForcedUnmount {
+ setmount 0;
+ return;
+}
+
diff --git a/npc/001-1/rumly.txt b/npc/001-1/rumly.txt
new file mode 100644
index 00000000..6cc625ff
--- /dev/null
+++ b/npc/001-1/rumly.txt
@@ -0,0 +1,225 @@
+// Evol scripts.
+// Author:
+// Vasily_Makarov
+// Description:
+// Stat resetter.
+// Variables:
+// General_Rumly
+// Values:
+// 0 Player hasn't met Rumly
+// 1 Last time player has told that he will never come back
+// 2 Last time player has told that he will come back later
+// 3 Player has already reset his stat
+// Others:
+// .@visited - Rumly actual variable
+// .@wasSP - free status points before reset
+
+001-1,35,125,0 script Rumly#001-1 NPC_RUMLY,{
+
+ setnpcdir "Rumly#001-1", 2;
+ stopnpctimer;
+ initnpctimer;
+
+ speech S_LAST_NEXT,
+ l("Hey you, do you have any @@s?", getitemlink(Plushroom));
+
+L_Menu:
+ .@visited = getq(General_Rumly);
+ .@plush_count = lognbaselvl(1, 10);
+
+ select
+ l("Plushrooms you say?"),
+ l("Who are you?"),
+ rif(.@visited > 0, l("Can you reset my stats please?")),
+ l("You are weird, I have to go sorry.");
+
+ switch (@menu)
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Wind and grass is nice and cool, so juicy sweet..."),
+ l("Our only wish to eat a plush, so juicy sweet...");
+ goto L_Menu;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Why are you asking? And who are you too? I've never seen you around before..."),
+ l("Wait, are you one of those from the Legion of Gasaron? I didn't do anything wrong, I promise!"),
+ l("I... I just like to eat the purple and delightful... And natural, and...");
+
+ switch (select(l("Chill out I won't say anything."),
+ l("Yes I am and you are going to face justice!")))
+ {
+ case 1: break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("No! No, no, my precious plushrooms! Don’t take me to them, they wants my precious.");
+ goto L_Quit;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I won't forget it, I swear on my precious plushrooms!"),
+ l("There is an unknown side effect to these plushrooms, they can free you from your past mistakes."),
+ l("You can use it to clear your stats, to start freshly if you see what I mean..."),
+ l("Bring me some of these plushrooms and I will show you how it works!"),
+ l("Although the more powerful you are, the more plushrooms you will need.");
+
+ select
+ l("Sounds good!"),
+ rif(countitem(Plushroom) >= .@plush_count, l("I think I have enough plushrooms on me.")),
+ l("We will talk about it later."),
+ l("My stats are too good, I won't need it.");
+
+ switch (@menu)
+ {
+ case 1:
+ if (.@visited < 2)
+ {
+ setq General_Rumly, 2;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Great! Can't wait for some tasty mushrooms!");
+
+ goto L_Menu;
+ case 2:
+ goto L_ResetStats;
+ case 3:
+ goto L_Later;
+ case 4:
+ goto L_Never;
+ }
+
+ case 3:
+ goto L_ResetStats;
+ case 4:
+ if (.@visited < 2) goto L_Quit;
+
+ .@rand = rand(2);
+
+ if (.@rand)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("See you! And come back with the plushrooms!");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh noes!"),
+ l("A rabbit!"),
+ l("He has a guns!"),
+ l("*Bang bang*");
+ narrator S_LAST_NEXT,
+ l("Rumly is hiding behind the tree.");
+ }
+
+ goto L_Quit;
+ }
+
+L_ResetStats:
+ if (.@visited == 1)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Changed your mind, uh?"),
+ l("Very good."),
+ l("Status point reset can't be undone. Do you really want this?"),
+ l("Are you sure about this?");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Are you sure about this?");
+ }
+
+L_ConfirmReset:
+ switch (select(l("Yes, I am sure."),
+ l("I need to think about it..."),
+ l("I won't need it, thank you.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Let me just have a quick look at you. Hm... I will need @@ @@s to reset your stats.", .@plush_count, getitemlink(Plushroom));
+
+ select
+ rif(countitem(Plushroom) >= .@plush_count, l("Here, take as many as you need, I have plenty!")),
+ rif(countitem(Plushroom) > 0 && countitem(Plushroom) < .@plush_count, l("I don't have enough plushrooms...")),
+ rif(countitem(Plushroom) == 0, l("Oh no, I don't have any plushroom on me right now.")),
+ l("I have to go, sorry.");
+
+ if (@menu > 1)
+ {
+ goto L_Later;
+ }
+
+ delitem Plushroom, .@plush_count;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thank you."),
+ l("Now stand still... It should not take much time...");
+
+ .@wasSP = StatusPoint;
+ resetstatus;
+ if (.@visited < 3)
+ {
+ setq General_Rumly, 3;
+ }
+ if (StatusPoint == .@wasSP)
+ {
+ speech S_LAST_NEXT,
+ l("It seems that you have no status points to reset!"),
+ l("But the plushroom you brought was really awesome you know."),
+ l("Come back when you will really need me. And bring more plushrooms with you!");
+ }
+ else
+ {
+ speech S_LAST_NEXT,
+ l("Let's see... @@ of your status points have just been reset!", StatusPoint - .@wasSP),
+ l("Spend it wisely this time."),
+ l("But you are welcome to reset your stats again if you bring me some more plushrooms!");
+ }
+ goto L_Quit;
+
+ case 2:
+ goto L_Later;
+ case 3:
+ goto L_Never;
+ }
+
+L_Later:
+ if (.@visited < 2)
+ {
+ setq General_Rumly, 2;
+ }
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Come back soon, and bring @@s!", getitemlink(Plushroom));
+
+ goto L_Quit;
+
+L_Never:
+ if (.@visited < 2)
+ {
+ setq General_Rumly, 1;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I am sure that you will change your mind.");
+
+ goto L_Quit;
+
+L_Quit:
+ setnpcdir "Rumly#001-1", 4;
+ stopnpctimer;
+ initnpctimer;
+
+ goodbye;
+
+OnTimer1800:
+ stopnpctimer;
+
+ if (getnpcdir("Rumly#001-1") == 2) setnpcdir "Rumly#001-1", 6;
+ if (getnpcdir("Rumly#001-1") == 4) setnpcdir "Rumly#001-1", 8;
+
+ end;
+
+OnInit:
+ end;
+}
diff --git a/npc/001-1/salem.txt b/npc/001-1/salem.txt
new file mode 100644
index 00000000..913db476
--- /dev/null
+++ b/npc/001-1/salem.txt
@@ -0,0 +1,219 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Description:
+// Trader on the market. One of his pious escaped and
+// flies around the town.
+// Variables:
+// ArtisQuests_CatchPiou -- quest variable
+// Quest states:
+// 0 -- not started
+// 1 -- trader asked to catch piou
+// 2 -- quest finished
+// Note: this script is ugly like hell
+
+001-1,57,118,0 script Salem#001-1 NPC_SALEM,{
+
+ function BuyPiou {
+ .@price = getarg(0);
+ mesq l("The piou costs @@ E.", .@price);
+ next;
+ select
+ l("Alright, I'll take one."),
+ l("I changed my mind.");
+
+ mes "";
+ mesn;
+ if (@menu == 2)
+ return 4;
+ if (Zeny < .@price)
+ {
+ mesq l("Don't you try to cheat an old merchant! You don't have enough money, you need @@ E.", .@price);
+ next;
+
+ return 1;
+ }
+ if (!checkweight(PiouEgg, 1))
+ {
+ mesq l("You can't carry another @@? What a shame.", PiouEgg);
+ next;
+
+ return 2;
+ }
+ getinventorylist;
+ if (.@inventorylist_count >= 100)
+ {
+ mesq l("You don't have enough room in your backpack for a @@. Go stow some of your junk and come back.", PiouEgg);
+ next;
+
+ return 3;
+ }
+ Zeny -= .@price;
+ getitem PiouEgg, 1;
+ ArtisQuests_PiousBought += 1;
+ mesq l("You take good care of your piou. Remember to feed it every day.");
+
+ return 0;
+ }
+
+// if (2 == select("[debug]continue quest:[debug] start over"))
+// {
+// debugmes "Starting quest CatchPiou over";
+// setq ArtisQuests_CatchPiou, 0;
+// }
+
+ .@q = getq(ArtisQuests_CatchPiou);
+ @ArtisQuests_PiouPrice = 30000;
+
+ if (.@q == 1)
+ {
+ if (.PiouCaught)
+ {
+ speech
+ l("Look who is back..."),
+ l("And with my piou. That's wonderful. I can only imagine how hard that little bugger was to catch!"),
+ l("Great, and as I promised, I give you a 90% discount on the @@ of your choice.", getitemlink(PiouEgg));
+ next;
+
+ @ArtisQuests_PiouPrice = 3000;
+ ArtisQuests_PiouDiscount = 1;
+ donpcevent strnpcinfo(3) + "::OnPiouFlee";
+ setq ArtisQuests_CatchPiou, 2;
+ .@q = getq(ArtisQuests_CatchPiou);
+
+ .LastPiouHunter$ = "";
+ ArtisQuests_CatchPiou_Difficulcy = 0;
+ .@BoughtPiou = BuyPiou(@ArtisQuests_PiouPrice);
+ if (.@BoughtPiou == 0)
+ ArtisQuests_PiouDiscount = 0;
+ else if (.@BoughtPiou == 4)
+ speech S_FIRST_BLANK_LINE, l("See you next time!");
+
+ close;
+ }
+ else
+ {
+ speech
+ l("Look who is back..."),
+ l("So, where is my piou? You should not keep an old man waiting. Go and catch it like you said you would.");
+ next;
+ goto L_SalemMenuShop;
+ }
+ }
+
+ speech S_LAST_NEXT,
+ l("Good day, my friend, come closer, come closer!");
+ l("Just look at my goods for sale! Fresh fruits and vegetables were shipped only this morning. And for reasonable price, of course.");
+
+L_SalemMenuShop:
+ .@fexil = getq(ArtisQuests_Fexil);
+
+ select
+ l("What about those pious? They look so cute."),
+ l("Let's trade."),
+ rif(.@q != 0, l("I'd like to buy a piou.")),
+ rif(.@fexil == 1, l("I'm looking for somebody named Fexil.")),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ goto L_AboutPious;
+ break;
+ case 2:
+ closeclientdialog;
+ shop "Store#General001-1";
+ close;
+ case 3:
+ if (.@q == 2 && ArtisQuests_PiouDiscount)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You still have a 90% discount on one piou.");
+ @ArtisQuests_PiouPrice = 3000;
+ }
+ if (!BuyPiou(@ArtisQuests_PiouPrice))
+ ArtisQuests_PiouDiscount = 0;
+ break;
+ case 4:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I think that I've seen this weakling wandering around the beach south from here this morning.");
+ break;
+ }
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+L_AboutPious:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ah, the locals like keeping them as pets."),
+ l("With proper training, a piou can become a good friend and faithful companion in your adventures.");
+
+ if (getq(ArtisQuests_CatchPiou) >= 2)
+ {
+ goto L_SalemMenuShop;
+ }
+
+ mesq l("Their price is usually high, but you know what? I have a bargain offer for you.");
+ next;
+ mesq l("These little pious here can't fly. At least that's what I thought.");
+ next;
+ mesq l("One of these little boogers started flying early, and escaped from me.");
+ next;
+ mesq l("It's still too young to fly too far away, so it just circles nearby.");
+ next;
+ mesq l("But I can't leave to catch it, so I'm asking you.");
+ next;
+ mesq l("If you catch the escaped piou and bring it back, I will give you a 90% discount on a piou.");
+ next;
+
+ select
+ rif(.@q == 0, l("Sounds like a good deal to me. I'll do it.")),
+ rif(.@q == 1, l("I'm on my way! I will bring it back to you.")),
+ l("I don't really have time to go chasing pious, let me just buy one at the regular price (30000 E)."),
+ l("I don't want to buy a piou right now.");
+
+ mes "";
+ mesn;
+
+ switch (@menu)
+ {
+ case 1:
+ goto L_QuestInfo;
+ case 3:
+ BuyPiou @ArtisQuests_PiouPrice;
+ }
+ closeclientdialog;
+ goodbye;
+ close;
+
+L_QuestInfo:
+ mesq l("The little piou is flying nearby, all you need is to catch it and bring back to me.");
+ next;
+ setq ArtisQuests_CatchPiou, 1;
+ ArtisQuests_CatchPiou_Difficulcy = 2;
+ mesq l("Good luck!");
+ close;
+
+OnPiouFlee:
+ sleep 120000;
+ if (!.PiouCaught)
+ end;
+ .PiouCaught = 0;
+ .@piou$ = "#FlyingPiou1";
+ if (getstrlen(.LastPiouHunter$) > 0)
+ {
+ message .LastPiouHunter$, .PiouEscapedMessage$;
+ .LastPiouHunter$ = "";
+ }
+ // debugmes "The piou escaped from " + .LastPiouHunter$;
+ sleep 60000;
+ enablenpc .@piou$;
+ movenpc .@piou$, 53, 117;
+ donpcevent .@piou$ + "::OnInit";
+ end;
+
+OnInit:
+ .distance = 5;
+ end;
+}
diff --git a/npc/001-1/shop.txt b/npc/001-1/shop.txt
new file mode 100644
index 00000000..f33ee4ac
--- /dev/null
+++ b/npc/001-1/shop.txt
@@ -0,0 +1,298 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Market shops.
+
+001-1,46,135,0 trader Bag#001-1 NPC_SHOP_BAG,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem PiouLegs, -1, 15;
+ sellitem Bread, -1, 15;
+ sellitem Croconut, -1, 50;
+ sellitem Aquada, -1, 50;
+ sellitem Armbands, -1, 20;
+ sellitem LousyMoccasins, -1, 20;
+ sellitem PiouSlayer, -1, 15;
+
+ .distance = 3;
+ end;
+
+OnClock0000:
+ restoreshopitem PiouLegs, 15;
+ restoreshopitem Bread, 15;
+ restoreshopitem Croconut, 50;
+ restoreshopitem Aquada, 50;
+ restoreshopitem Armbands, 20;
+ restoreshopitem LousyMoccasins, 20;
+ restoreshopitem PiouSlayer, 15;
+}
+
+001-1,46,125,0 trader Cotton#Dye001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem BlackCottonDye, -1, 10;
+ sellitem SilverCottonDye, -1, 10;
+ sellitem CamelCottonDye, -1, 10;
+ sellitem BrownCottonDye, -1, 10;
+ sellitem OrangeCottonDye, -1, 10;
+ sellitem DarkRedCottonDye, -1, 10;
+ sellitem RedCottonDye, -1, 10;
+ sellitem FuschiaCottonDye, -1, 10;
+ sellitem PinkCottonDye, -1, 10;
+ sellitem MauveCottonDye, -1, 10;
+ sellitem PurpleCottonDye, -1, 10;
+ sellitem NavyBlueCottonDye, -1, 10;
+ sellitem BlueGrayCottonDye, -1, 10;
+ sellitem BlueCottonDye, -1, 10;
+ sellitem TealCottonDye, -1, 10;
+ sellitem GreenCottonDye, -1, 10;
+ sellitem LimeCottonDye, -1, 10;
+ sellitem KhakiCottonDye, -1, 10;
+ sellitem YellowCottonDye, -1, 10;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem BlackCottonDye, 10;
+ restoreshopitem SilverCottonDye, 10;
+ restoreshopitem CamelCottonDye, 10;
+ restoreshopitem BrownCottonDye, 10;
+ restoreshopitem OrangeCottonDye, 10;
+ restoreshopitem DarkRedCottonDye, 10;
+ restoreshopitem RedCottonDye, 10;
+ restoreshopitem FuschiaCottonDye, 10;
+ restoreshopitem PinkCottonDye, 10;
+ restoreshopitem MauveCottonDye, 10;
+ restoreshopitem PurpleCottonDye, 10;
+ restoreshopitem NavyBlueCottonDye, 10;
+ restoreshopitem BlueGrayCottonDye, 10;
+ restoreshopitem BlueCottonDye, 10;
+ restoreshopitem TealCottonDye, 10;
+ restoreshopitem GreenCottonDye, 10;
+ restoreshopitem LimeCottonDye, 10;
+ restoreshopitem KhakiCottonDye, 10;
+ restoreshopitem YellowCottonDye, 10;
+}
+
+001-1,48,125,0 trader Silk#Dye001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem PitchBlackSilkDye, -1, 7;
+ sellitem ChocolateSilkDye, -1, 7;
+ sellitem CrimsonSilkDye, -1, 7;
+ sellitem TomatoSilkDye, -1, 7;
+ sellitem GoldenrodSilkDye, -1, 7;
+ sellitem SunflowerSilkDye, -1, 7;
+ sellitem OliveSilkDye, -1, 7;
+ sellitem SeaGreenSilkDye, -1, 7;
+ sellitem MintSilkDye, -1, 7;
+ sellitem MidnightBlueSilkDye, -1, 7;
+ sellitem SlatBlueSilkDye, -1, 7;
+ sellitem OrchidSilkDye, -1, 7;
+ sellitem PinkiePinkSilkDye, -1, 7;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem PitchBlackSilkDye, -1, 7;
+ restoreshopitem ChocolateSilkDye, -1, 7;
+ restoreshopitem CrimsonSilkDye, -1, 7;
+ restoreshopitem TomatoSilkDye, -1, 7;
+ restoreshopitem GoldenrodSilkDye, -1, 7;
+ restoreshopitem SunflowerSilkDye, -1, 7;
+ restoreshopitem OliveSilkDye, -1, 7;
+ restoreshopitem SeaGreenSilkDye, -1, 7;
+ restoreshopitem MintSilkDye, -1, 7;
+ restoreshopitem MidnightBlueSilkDye, -1, 7;
+ restoreshopitem SlatBlueSilkDye, -1, 7;
+ restoreshopitem OrchidSilkDye, -1, 7;
+ restoreshopitem PinkiePinkSilkDye, -1, 7;
+}
+
+001-1,64,114,0 trader Store#Aquada001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem Aquada, -1, 50;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem Aquada, 20;
+OnClock0800:
+ restoreshopitem Aquada, 20;
+OnClock1600:
+ restoreshopitem Aquada, 20;
+}
+
+001-1,72,126,0 trader Store#SeaStore001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem Aquada, -1, 10;
+ sellitem UrchinMeat, -1, 20;
+ sellitem SmallTentacles, -1, 30;
+ sellitem Tentacles, -1, 15;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem Aquada, 3;
+ restoreshopitem UrchinMeat, 12;
+ restoreshopitem SmallTentacles, 4;
+OnClock0800:
+ restoreshopitem Aquada, 6;
+ restoreshopitem UrchinMeat, 8;
+ restoreshopitem Tentacles, 8;
+ restoreshopitem SmallTentacles, 2;
+OnClock1600:
+ restoreshopitem Aquada, 5;
+ restoreshopitem UrchinMeat, 10;
+ restoreshopitem SmallTentacles, 7;
+}
+
+001-1,72,129,0 trader Store#FishStore001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem CommonCarp, -1, 8;
+ sellitem GrassCarp, -1, 7;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem CommonCarp, 3;
+ restoreshopitem GrassCarp, 2;
+OnClock0800:
+ restoreshopitem CommonCarp, 2;
+ restoreshopitem GrassCarp, 3;
+OnClock1600:
+ restoreshopitem CommonCarp, 3;
+ restoreshopitem GrassCarp, 4;
+}
+
+001-1,48,116,0 trader Store#Manana001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem Manana, -1, 60;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem Manana, 20;
+OnClock0800:
+ restoreshopitem Manana, 15;
+OnClock1600:
+ restoreshopitem Manana, 20;
+}
+
+001-1,53,123,0 trader Store#Various001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem Manana, -1, 30;
+// Add soft drinks.
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem Manana, 10;
+OnClock0800:
+ restoreshopitem Manana, 15;
+OnClock1600:
+ restoreshopitem Manana, 6;
+}
+
+001-1,67,116,0 trader Store#Potion001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem PiberriesInfusion, -1, 200;
+ sellitem FatesPotion, -1, 100;
+ sellitem ClothoLiquor, -1, 50;
+ sellitem LachesisBrew, -1, 30;
+ sellitem AtroposMixture, -1, 10;
+ sellitem ElixirOfLife, -1, 1;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem PiberriesInfusion, 150;
+ restoreshopitem FatesPotion, 80;
+ restoreshopitem ClothoLiquor, 40;
+ restoreshopitem LachesisBrew, 20;
+ restoreshopitem AtroposMixture, 7;
+ restoreshopitem ElixirOfLife, 1;
+OnClock1200:
+ restoreshopitem PiberriesInfusion, 80;
+ restoreshopitem FatesPotion, 40;
+ restoreshopitem ClothoLiquor, 20;
+ restoreshopitem LachesisBrew, 10;
+ restoreshopitem AtroposMixture, 4;
+}
+
+001-1,58,119,0 trader Store#General001-1 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem Manana, -1, 100;
+ sellitem Carrot, -1, 80;
+ sellitem Aquada, -1, 50;
+ sellitem Plushroom, -1, 100;
+ sellitem Curshroom, -1, 80;
+ sellitem Piberries, -1, 150;
+ sellitem PiouEgg, -1, 25;
+// Add soft drinks.
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+ restoreshopitem Manana, 50;
+ restoreshopitem Carrot, 40;
+ restoreshopitem Aquada, 30;
+ restoreshopitem Plushroom, 40;
+ restoreshopitem Curshroom, 30;
+ restoreshopitem Piberries, 40;
+ restoreshopitem PiouEgg, 10;
+OnClock0800:
+ restoreshopitem Manana, 30;
+ restoreshopitem Carrot, 30;
+ restoreshopitem Aquada, 30;
+ restoreshopitem Plushroom, 40;
+ restoreshopitem Curshroom, 30;
+ restoreshopitem Piberries, 70;
+ restoreshopitem PiouEgg, 10;
+OnClock1600:
+ restoreshopitem Manana, 40;
+ restoreshopitem Carrot, 40;
+ restoreshopitem Aquada, 20;
+ restoreshopitem Plushroom, 20;
+ restoreshopitem Curshroom, 20;
+ restoreshopitem Piberries, 30;
+ restoreshopitem PiouEgg, 5;
+}
diff --git a/npc/001-1/sign.txt b/npc/001-1/sign.txt
new file mode 100644
index 00000000..ecd115be
--- /dev/null
+++ b/npc/001-1/sign.txt
@@ -0,0 +1,168 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Reid
+// Description:
+// Sign pillars aside Artis houses.
+
+001-1,73,119,0 script Sign#001-1-s-market NPC_NO_SPRITE,{
+ npctalkonce l("Market Place");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,48,122,0 script Sign#001-1-s-marketright NPC_NO_SPRITE,{
+ npctalkonce l("Market Place");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,57,88,0 script Sign#001-1-s-marketdir NPC_NO_SPRITE,{
+ npctalkonce l("↓ Market Place");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,55,86,0 script Sign#001-1-s-exit-l-dir NPC_NO_SPRITE,{
+ npctalkonce l("← Exit");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,59,85,0 script Sign#001-1-s-legiondir NPC_NO_SPRITE,{
+ npctalkonce l("↑ Legion");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,57,80,0 script Sign#001-1-s-library NPC_NO_SPRITE,{
+ npctalkonce l("Library");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,57,71,0 script Sign#001-1-s-lightarmor NPC_NO_SPRITE,{
+ npctalkonce l("Light Armor Shop");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,53,56,0 script Sign#001-1-s-legion NPC_OFFSET_NO_SPRITE,{
+ npctalkonce l("Legion of Aemil");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,60,56,0 script Sign#001-1-s-legionright NPC_OFFSET_NO_SPRITE,{
+ npctalkonce l("Legion of Aemil");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,91,66,0 script Sign#001-1-s-cityhall NPC_NO_SPRITE,{
+ npctalkonce l("City Hall");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,95,111,0 script Sign#001-1-s-blacksmith NPC_NO_SPRITE,{
+ npctalkonce l("Blacksmith");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,115,88,0 script Sign#001-1-s-inn NPC_NO_SPRITE,{
+ npctalkonce l("Inn");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,134,85,0 script Sign#001-1-s-innright NPC_OFFSET_NO_SPRITE,{
+ npctalkonce l("Inn");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,118,36,0 script Sign#001-1-s-merchantg NPC_NO_SPRITE,{
+ npctalkonce l("Merchant Guild");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,171,48,0 script Sign#001-1-s-hill NPC_OFFSET_NO_SPRITE,{
+ npctalkonce l("Hill & Cliff");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,161,72,0 script Sign#001-1-s-alchemist NPC_NO_SPRITE,{
+ npctalkonce l("Alchemist's Laboratory");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,175,76,0 script Sign#001-1-s-warehouse NPC_NO_SPRITE,{
+ npctalkonce l("Docks Warehouse");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,47,97,0 script Sign#001-1-s-barber NPC_NO_SPRITE,{
+ npctalkonce l("Barber");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
diff --git a/npc/001-1/sophialla.txt b/npc/001-1/sophialla.txt
new file mode 100644
index 00000000..f44ef218
--- /dev/null
+++ b/npc/001-1/sophialla.txt
@@ -0,0 +1,88 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Sophialla, the connection between Artis and the Brotherhood in Hurns.
+// THIS IS A PLACEHOLDER!
+
+001-1,73,40,0 script Sophialla#001-1 NPC_SOPHIALLA,{
+ .@q=getq(General_Brotherhood);
+ if (!.@q)
+ {
+ speech
+ l("Hello."),
+ l("Can't you see I am reading? Please go, please.");
+ // Please go, please? What?
+ close;
+ }
+ speech
+ l("Hello."),
+ l("Can't you see I am reading? If you need something, tell me the secret password.");
+ // TODO: Use a token to know password or whatever
+ // PS. "Sagratha" is not a typo.
+ select
+ l("Sorry to disturb you."),
+ rif(getq(ArtisQuests_MonaDad) == 3, l("Sagratha is great.")),
+ l("I don't know the password");
+ mes "";
+ if (@menu == 2)
+ {
+ speech
+ l("If you visit the sewers again... You'll find secret passages..."),
+ l("Look for the hideout, but tell no one about this. Then, say the password again.");
+ compareandsetq General_Brotherhood, 1, 2;
+ }
+ else if (@menu == 3)
+ {
+ mesn;
+ mesq l("If I just told you, it would not be a password anymore, right?");
+ next;
+ mesn;
+ mesq l("I'm afraid you'll need to figure that out on your own.");
+ next;
+ mesn;
+ mesq l("This password is very secret. I don't think you would learn it even if you rescued someone missing for weeks.");
+ // Extra hint (TODO: Logic is crappy)
+ if (@sophiahalla_needhelp) {
+ next;
+ mesn;
+ mesq l("Actually, there is an ex-legion member whose daughter used to play nearby... How was she called? Mona I think?");
+ next;
+ mesn;
+ mesq l("...Ah! Nevermind, I was talking to myself.");
+ }
+ @sophiahalla_needhelp=true;
+ next;
+ mesc l("%s sighs.", .name$);
+ }
+
+ speech
+ l("If you don't know it, just go, please.");
+ close;
+
+OnLegionComplete:
+ restorecam;
+ mesn "???";
+ mesc l("A strange voice seems to be calling out your name.");
+ next;
+ // NOTE: Sophialla is more than 15 tiles of distance from player
+ // Server refuses to send client data about where she is and that makes
+ // setcamnpc fail. This is why I set .alwaysVisible attribute to true.
+ // Note: you can work around with coordinates, but she won't be drawn.
+ setcamnpc "Sophialla#001-1";
+ mesn;
+ mesq l("Hey. ppst. I have something important to tell you.");
+ next;
+ mesn;
+ mesq l("I just can't remember what. But come talk to me later once devs becomes less lazy.");
+ setq General_Brotherhood, 1;
+ next;
+ restorecam;
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ .alwaysVisible = true;
+ end;
+}
diff --git a/npc/001-1/taree.txt b/npc/001-1/taree.txt
new file mode 100644
index 00000000..676a855a
--- /dev/null
+++ b/npc/001-1/taree.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Mouboo farmer.
+
+001-1,68,79,0 script Taree NPC_ELVEN_MAN_MOUBOO_SHOP,{
+ mesn;
+ mesq l("Moo!");
+
+ goto L_Close;
+
+L_Close:
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-1/treeleaf.txt b/npc/001-1/treeleaf.txt
new file mode 100644
index 00000000..dd1280a6
--- /dev/null
+++ b/npc/001-1/treeleaf.txt
@@ -0,0 +1,22 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Reid
+// Description:
+// Falling tree leaf
+
+001-1,39,54,4 script #treeleaf0 NPC_TREE_LEAF,{
+ .dir = 2;
+ stopnpctimer;
+ initnpctimer;
+ close;
+
+OnTimer2800:
+ .dir = 4;
+ stopnpctimer;
+ end;
+
+OnInit:
+ .distance = 1;
+ end;
+}
diff --git a/npc/001-1/trees.txt b/npc/001-1/trees.txt
new file mode 100644
index 00000000..8e090218
--- /dev/null
+++ b/npc/001-1/trees.txt
@@ -0,0 +1,220 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Description:
+// Invisible tree NPCs for "Lazy Brother" quest
+// Variables:
+// ArtisQuests_LazyBrother = 19 -- quest var
+// LazyBrother_TreesLeft = 15 -- how many trees left to search
+// LazyBrother_TreeSearched[15] -- whether given tree was searched
+// LazyBrother_TreeWithBrother -- the number of tree where he's hiding
+// Quest states:
+// 0 - quest not started
+// 1 - Katja asked help, searching the trees
+// 2 - Bobo is found, "bad" ending
+// 3 - player decided to tell Katja where her brother is
+// 4 - "good" ending, player helped Katja
+
+function script LazyBrotherTreeFunc {
+ .@q = getq(ArtisQuests_LazyBrother);
+ if (.@q == 0 || .@q >= 2)
+ return;
+ .@TreeNum = getarg(0);
+ if (LazyBrother_TreeWithBrother == .@TreeNum)
+ goto L_FoundHim;
+ if (LazyBrother_TreeWithBrother > 0)
+ {
+ mes l("You search the tree but don't find anybody.");
+ close2;
+ return;
+ }
+ if (LazyBrother_TreeSearched[.@TreeNum] == 1)
+ {
+ mes l("You already looked here.");
+ close2;
+ return;
+ }
+ else
+ {
+ LazyBrother_TreeSearched[.@TreeNum] = 1;
+ }
+ .@found = rand(1, LazyBrother_TreesLeft--);
+ if (.@found == 1)
+ {
+ mes l("You found him!");
+ LazyBrother_TreeWithBrother = .@TreeNum;
+ next;
+ }
+ else
+ {
+ mes l("You search the tree but don't find anybody.");
+ close2;
+ return;
+ }
+
+L_FoundHim:
+ mes l("You notice a young boy sitting on one of the highest branches of the tree.");
+ next;
+ mes l("He is eating an apple, thoroughly enjoying it.");
+ next;
+ select(l("Hey there, are you Bobo, Katja's brother?"));
+ mes "";
+ mesn "Bobo";
+ mesq l("Yes, it's me. It's such a fine view from here!");
+ next;
+ select(l("Your sister sent me to find you. Your mother is worried."));
+ mes "";
+ mesn "Bobo";
+ mesq l("Oh, nooooo... If I go home now, my mum will give me chores.");
+ next;
+ mesq l("But if you tell my sister, that you didn't find me, I can stay here all day, eating apples and enjoying the view.");
+ next;
+ mesq l("I will give you my pocket money if you do.");
+ next;
+ switch (select(l("A small lie is really just a fib, and I could really use some cash..."),
+ l("I will not lie to a little girl! And your mother needs your help.")))
+ {
+ case 1:
+ mes "";
+ mesn "Bobo";
+ mesq l("Here you go.");
+ next;
+ mesn "Narrator";
+ mes l("Somehow you don't feel good about your deed.");
+ // Karma -= 2;
+ setq ArtisQuests_LazyBrother, 2;
+ Zeny += 100;
+ getexp 500, 0;
+ break;
+ case 2:
+ mes "";
+ mesn "Bobo";
+ mesq l("Okay... Tell my sister I'll go home soon.");
+ setq ArtisQuests_LazyBrother, 3;
+ break;
+ }
+ LazyBrother_TreesLeft = 0;
+ LazyBrother_TreeWithBrother = 0;
+ cleararray LazyBrother_TreeSearched,0,15;
+ close;
+}
+
+001-1,179,30,0 script #ArtisTree1 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(1);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,177,29,0 script #ArtisTree2 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(2);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,183,28,0 script #ArtisTree3 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(3);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,182,25,0 script #ArtisTree4 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(4);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,187,26,0 script #ArtisTree5 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(5);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,189,28,0 script #ArtisTree6 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(6);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,184,30,0 script #ArtisTree7 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(7);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,189,31,0 script #ArtisTree8 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(8);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,191,30,0 script #ArtisTree9 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(9);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,191,33,0 script #ArtisTree10 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(10);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,187,34,0 script #ArtisTree11 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(11);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,185,35,0 script #ArtisTree12 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(12);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,182,34,0 script #ArtisTree13 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(13);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,180,33,0 script #ArtisTree14 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(14);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-1,181,32,0 script #ArtisTree15 NPC_KATJA_TREE,{
+ LazyBrotherTreeFunc(15);
+ end;
+OnInit:
+ .distance = 1;
+ end;
+}
diff --git a/npc/001-1/wateranimation.txt b/npc/001-1/wateranimation.txt
new file mode 100644
index 00000000..eb9acc9d
--- /dev/null
+++ b/npc/001-1/wateranimation.txt
@@ -0,0 +1,23 @@
+// Evol scripts.
+// Author:
+// gumi
+// Reid
+// Description:
+// Water animations, splash, fishes, etc...
+
+001-1,116,123,0 duplicate(#fish_basic) #water_animation0 NPC_WATER_SPLASH
+001-1,119,102,0 duplicate(#fish_basic) #water_animation1 NPC_WATER_SPLASH
+001-1,167,82,0 duplicate(#fish_basic) #water_animation2 NPC_WATER_SPLASH
+001-1,167,40,0 duplicate(#fish_basic) #water_animation3 NPC_WATER_SPLASH
+001-1,104,127,0 duplicate(#fish_basic) #water_animation4 NPC_WATER_SPLASH
+001-1,166,123,0 duplicate(#fish_basic) #water_animation5 NPC_WATER_SPLASH
+001-1,181,119,0 duplicate(#fish_basic) #water_animation6 NPC_WATER_SPLASH
+001-1,202,114,0 duplicate(#fish_basic) #water_animation7 NPC_WATER_SPLASH
+001-1,187,86,0 duplicate(#fish_basic) #water_animation8 NPC_WATER_SPLASH
+001-1,32,57,0 duplicate(#fish_basic) #water_animation9 NPC_WATER_SPLASH
+001-1,40,144,0 duplicate(#fish_basic) #water_animation10 NPC_WATER_SPLASH
+001-1,58,131,0 duplicate(#fish_basic) #water_animation11 NPC_WATER_SPLASH
+001-1,76,137,0 duplicate(#fish_basic) #water_animation12 NPC_WATER_SPLASH
+001-1,109,132,0 duplicate(#fish_basic) #water_animation13 NPC_WATER_SPLASH
+001-1,141,93,0 duplicate(#fish_basic) #water_animation14 NPC_WATER_SPLASH
+001-1,168,57,0 duplicate(#fish_basic) #water_animation15 NPC_WATER_SPLASH
diff --git a/npc/001-1/xilaxa.txt b/npc/001-1/xilaxa.txt
new file mode 100644
index 00000000..e1e66e91
--- /dev/null
+++ b/npc/001-1/xilaxa.txt
@@ -0,0 +1,50 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Moon, main NPC for the urchin quest.
+
+001-1,52,44,0 script Xilaxa#001-1 NPC_UKAR_MALE_LEGION_ARTIS,{
+
+ npc_pausemove();
+ getmapxy(.@map$, .@cx, .@cy, 0);
+ npc_turntoxy(.@cx, .@cy);
+ npctalkonce("Hello.");
+ npc_resumemove();
+ close;
+
+OnTimer1000:
+ dographmovestep;
+
+OnInit:
+ .distance = 5;
+ initmovegraph "mid", 54, 43, 60, 46,
+ "left", 47, 50, 52, 55,
+ "right", 62, 50, 67, 55;
+
+ setmovegraphcmd "mid", "left", 1, "dir 0; wait 4",
+ "mid", "left", 4, "dir 2; wait 3; dir 0; wait 2; dir 6; wait 1; dir 0",
+ "mid", "left", 2, "dir 4; wait 5; dir 0; wait 2",
+ "mid", "left", 3, "dir 6; wait 1; dir 0; wait 3; dir 2; wait 3; dir 0",
+ "mid", "left", 1, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+ "mid", "right", 3, "dir 0; wait 4",
+ "mid", "right", 4, "dir 2; wait 3; dir 0; wait 2; dir 6; wait 1; dir 0",
+ "mid", "right", 2, "dir 4; wait 5; dir 0; wait 2",
+ "mid", "right", 1, "dir 6; wait 1; dir 0; wait 3; dir 2; wait 3; dir 0",
+ "mid", "right", 2, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+
+ "left", "mid", 2, "dir 0; wait 4",
+ "left", "mid", 1, "dir 2; wait 3; dir 0; wait 2; dir 6; wait 1; dir 0",
+ "left", "mid", 3, "dir 4; wait 5; dir 0; wait 2",
+ "left", "mid", 2, "dir 6; wait 1; dir 0; wait 3; dir 2; wait 3; dir 0",
+ "left", "mid", 3, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5",
+
+ "right", "mid", 3, "dir 0; wait 4",
+ "right", "mid", 2, "dir 2; wait 3; dir 0; wait 2; dir 6; wait 1; dir 0",
+ "right", "mid", 1, "dir 4; wait 5; dir 0; wait 2",
+ "right", "mid", 1, "dir 6; wait 1; dir 0; wait 3; dir 2; wait 3; dir 0",
+ "right", "mid", 2, "dir 0; wait 1; dir 2; wait 1; dir 0; wait 1; dir 6; wait 5";
+
+ firstmove "wait 5", "mid";
+ initnpctimer;
+}
diff --git a/npc/001-2-0/_import.txt b/npc/001-2-0/_import.txt
new file mode 100644
index 00000000..2fb6a262
--- /dev/null
+++ b/npc/001-2-0/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-0: Light Armor Shop
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-0/_warps.txt",
+"npc/001-2-0/mapflags.txt",
+"npc/001-2-0/resa.txt",
+"npc/001-2-0/shop.txt",
diff --git a/npc/001-2-0/_warps.txt b/npc/001-2-0/_warps.txt
new file mode 100644
index 00000000..c81b7fa6
--- /dev/null
+++ b/npc/001-2-0/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-0: Light Armor Shop warps
+001-2-0,30,35,0 warp #001-2-0_30_35 0,0,001-1,51,66
+001-2-0,37,46,0 warp #001-2-0_37_46 0,0,001-1,55,72
diff --git a/npc/001-2-0/mapflags.txt b/npc/001-2-0/mapflags.txt
new file mode 100644
index 00000000..a1781431
--- /dev/null
+++ b/npc/001-2-0/mapflags.txt
@@ -0,0 +1 @@
+001-2-0 mapflag town
diff --git a/npc/001-2-0/resa.txt b/npc/001-2-0/resa.txt
new file mode 100644
index 00000000..160b8351
--- /dev/null
+++ b/npc/001-2-0/resa.txt
@@ -0,0 +1,79 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Light Armor shop keeper.
+// Variables:
+// ArtisQuests_Enora
+// Values:
+// 0 Default.
+// 1 BlackSmith quest delivered.
+// 2 Chelios Quest given.
+// 3 Chelios Quest done.
+// 4 BlackSmith gave the sword.
+// 5 Light Armor Shop quest delivered.
+// 6 Light Armor Shop gave the cloths.
+
+001-2-0,37,28,0 script Resa NPC_ELVEN_FEMALE_ARMOR_SHOP,{
+
+ function explain_craft {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Did you see Don the blacksmith? He might know how you could improve your metal equipment."),
+ l("Nevertheless, you can craft some cards that you can then attach to your equipment."),
+ l("We sell a brimmed hat, you can craft a feather card and attach it to this hat to obtain an enhanced version of it!");
+
+ return;
+ }
+
+ function enora_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I thought that she would never come to pick it up!"),
+ l("Here it is, a fashionable @@.", getitemlink(ArtisTankTop, CamelCottonDye)),
+ l("I asked Calypsan to dye this tank top, now it has an unique look!");
+
+ narrator S_LAST_NEXT, l("You pick up the package.");
+
+ setq ArtisQuests_Enora, 6;
+
+ return;
+ }
+
+ speech S_LAST_NEXT,
+ l("Welcome to my office."),
+ l("What would you like today?");
+
+ do
+ {
+ .@enora = getq(ArtisQuests_Enora);
+ select
+ rif(.@enora == 5, l("I came to retrieve a package for Enora.")),
+ menuaction(l("Trade")),
+ l("How can I improve my equipment?"),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ enora_quest;
+ closeclientdialog;
+ goodbye;
+ close;
+ case 2:
+ closeclientdialog;
+ shop "Store#001-2-0";
+ close;
+ case 3:
+ explain_craft;
+ break;
+ case 4:
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+ } while (1);
+
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-0/shop.txt b/npc/001-2-0/shop.txt
new file mode 100644
index 00000000..eccc812c
--- /dev/null
+++ b/npc/001-2-0/shop.txt
@@ -0,0 +1,34 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Light armor shop.
+
+001-2-0,37,29,0 trader Store#001-2-0 NPC_NO_SPRITE,{
+// The ArtisTankTop should be store at x: 39 or 40, y: 31.
+// 38,35 is server's location of where client displays a black torso gear on display. (using @where for server).
+// 35,27 is some shelves and a cabinet at 4 tiles from where player select it.
+// 39,27 is where to put store that sells only fabric. (the cloth shelf).
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem ArtisTankTop, -1, 50;
+ sellitem VneckJumper, -1, 30;
+ sellitem BrownTrousers, -1, 30;
+ sellitem BrimmedHat, -1, 35;
+
+ .distance = 2;
+ end;
+
+OnClock0000:
+ restoreshopitem ArtisTankTop, 30;
+ restoreshopitem VneckJumper, 12;
+ restoreshopitem BrownTrousers, 15;
+ restoreshopitem BrimmedHat, 10;
+OnClock1200:
+ restoreshopitem ArtisTankTop, 25;
+ restoreshopitem VneckJumper, 10;
+ restoreshopitem BrownTrousers, 10;
+ restoreshopitem BrimmedHat, 20;
+}
diff --git a/npc/001-2-1/_import.txt b/npc/001-2-1/_import.txt
new file mode 100644
index 00000000..85933242
--- /dev/null
+++ b/npc/001-2-1/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-1: Noble House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-1/_savepoints.txt",
+"npc/001-2-1/_warps.txt",
+"npc/001-2-1/mapflags.txt",
diff --git a/npc/001-2-1/_savepoints.txt b/npc/001-2-1/_savepoints.txt
new file mode 100644
index 00000000..fa9c1ecc
--- /dev/null
+++ b/npc/001-2-1/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-1: Noble House saves
+001-2-1,27,30,0 script #save_001-2-1_27_30 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-1/_warps.txt b/npc/001-2-1/_warps.txt
new file mode 100644
index 00000000..1189adc7
--- /dev/null
+++ b/npc/001-2-1/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-1: Noble House warps
+001-2-1,37,41,0 warp #001-2-1_37_41 0,0,001-1,128,31
diff --git a/npc/001-2-1/mapflags.txt b/npc/001-2-1/mapflags.txt
new file mode 100644
index 00000000..07cacd14
--- /dev/null
+++ b/npc/001-2-1/mapflags.txt
@@ -0,0 +1 @@
+001-2-1 mapflag town
diff --git a/npc/001-2-10/_import.txt b/npc/001-2-10/_import.txt
new file mode 100644
index 00000000..7c1b01d6
--- /dev/null
+++ b/npc/001-2-10/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-10: Noble House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-10/_savepoints.txt",
+"npc/001-2-10/_warps.txt",
+"npc/001-2-10/mapflags.txt",
diff --git a/npc/001-2-10/_savepoints.txt b/npc/001-2-10/_savepoints.txt
new file mode 100644
index 00000000..91b14f37
--- /dev/null
+++ b/npc/001-2-10/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-10: Noble House saves
+001-2-10,26,30,0 script #save_001-2-10_26_30 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-10/_warps.txt b/npc/001-2-10/_warps.txt
new file mode 100644
index 00000000..e9e39231
--- /dev/null
+++ b/npc/001-2-10/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-10: Noble House warps
+001-2-10,27,45,0 warp #001-2-10_27_45 0,0,001-1,118,50
+001-2-10,51,45,0 warp #001-2-10_51_45 0,0,001-1,135,50
diff --git a/npc/001-2-10/mapflags.txt b/npc/001-2-10/mapflags.txt
new file mode 100644
index 00000000..bf833609
--- /dev/null
+++ b/npc/001-2-10/mapflags.txt
@@ -0,0 +1 @@
+001-2-10 mapflag town
diff --git a/npc/001-2-11/_import.txt b/npc/001-2-11/_import.txt
new file mode 100644
index 00000000..7e5ac100
--- /dev/null
+++ b/npc/001-2-11/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-11: Noble House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-11/_savepoints.txt",
+"npc/001-2-11/_warps.txt",
+"npc/001-2-11/mapflags.txt",
+"npc/001-2-11/mona.txt",
diff --git a/npc/001-2-11/_savepoints.txt b/npc/001-2-11/_savepoints.txt
new file mode 100644
index 00000000..00b8c05c
--- /dev/null
+++ b/npc/001-2-11/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-11: Noble House saves
+001-2-11,26,31,0 script #save_001-2-11_26_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-11/_warps.txt b/npc/001-2-11/_warps.txt
new file mode 100644
index 00000000..648faa57
--- /dev/null
+++ b/npc/001-2-11/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-11: Noble House warps
+001-2-11,46,46,0 warp #001-2-11_46_46 0,0,001-1,148,55
diff --git a/npc/001-2-11/mapflags.txt b/npc/001-2-11/mapflags.txt
new file mode 100644
index 00000000..608ef1bd
--- /dev/null
+++ b/npc/001-2-11/mapflags.txt
@@ -0,0 +1 @@
+001-2-11 mapflag town
diff --git a/npc/001-2-11/mona.txt b/npc/001-2-11/mona.txt
new file mode 100644
index 00000000..f3a65651
--- /dev/null
+++ b/npc/001-2-11/mona.txt
@@ -0,0 +1,170 @@
+// Evol scripts.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// A rich girl holding a candle. Her father went to examine weird noises in the
+// sewers and still hasn't come back. Her mother is gone, but it is not clear
+// whether she died, abandoned them, or something else.
+// Variable:
+// MONA_TIME = gettimeparam(GETTIME_DAYOFMONTH) so you need 3 days
+// MONA_REPEAT = How many times the quest was done
+// ArtisQuests_MonaDad
+// Quest states:
+// 0 - Quest not started
+// 1 - Mona explained that her dad was missing
+// 2 - Player is bringing Mundane out of Sewers
+// 3 - Quest is complete
+// Note:
+// Any misformatted code is Jesusalva's fault.
+
+001-2-11,39,30,0 script Mona NPC_MONA,{
+
+ function find_daddy_quest
+ {
+ speech S_LAST_NEXT,
+ l("Hey you!");
+
+ switch (select(l("Yes?"), l("Sorry, I have to go.")))
+ {
+ case 1:
+ mes "";
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("No you don't have to go. I need your help, so you have to stay.");
+ break;
+ }
+
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("Daddy never came back home... He said that he would be back for lunch but it has already been two days!"),
+ l("You have to find him, or else I will tell him that you did not help me.");
+
+ switch (select(l("You do not give me a lot of options."), l("Your dad ran away from you!")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE,
+ l("He said that he would check why weird noises were coming from the manhole next to the house."),
+ l("But he never returned."),
+ l("Please find my daddy...");
+
+ setq ArtisQuests_MonaDad, 1;
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("I will tell my dad!");
+ break;
+ }
+ emotion E_SAD;
+ close;
+ }
+
+ // You're here to report that Mundane is out of the sewers.
+ // Forcing you to enter an instanced map would require more work.
+ // This means adding a warp NPC and a global instance.
+ // Global Instances get reset every 10 days or so, it would need a patch
+ // only to support Global Instances and in general is not a smart thing to do.
+ function check_daddy_quest
+ {
+ // Did you really bring Mundane to sewer exit?
+ // We need to add 1 tile in each direction of tolerance because addtimer()
+ // is not exactly what I would call “a reliable way to do stuff”
+ // Note that @variables sometimes get erasen AT RANDOM.
+ // If this problem happens, move it char variables.
+ // (that might cause problems with logout though.)
+ // Temporary variables give you a time limit to report back...
+ //
+ // There's no need to check if instance still exists, because
+ // when the instance expires, you get warped to *somewhere*.
+ // This means the timer will die and MUNDANE_OLD* variables will stop
+ // being updated.
+ .@success=false;
+
+ // Sewer mouths (warps to 001-1)
+ if (is_between(151, 153, @MUNDANE_OLDX) &&
+ is_between(55, 57, @MUNDANE_OLDY))
+ .@success=true;
+
+ if (is_between(195, 197, @MUNDANE_OLDX) &&
+ is_between(34, 36, @MUNDANE_OLDY))
+ .@success=true;
+
+ if (is_between(197, 199, @MUNDANE_OLDX) &&
+ is_between(59, 61, @MUNDANE_OLDY))
+ .@success=true;
+
+ if (is_between(84, 86, @MUNDANE_OLDX) &&
+ is_between(129, 131, @MUNDANE_OLDY))
+ .@success=true;
+
+ if (.@success)
+ return true;
+ else
+ return false;
+ }
+
+ // Here the script really starts
+ if (getq(ArtisQuests_MonaDad) == 0)
+ {
+ find_daddy_quest();
+ }
+ else if (getq(ArtisQuests_MonaDad) == 3)
+ {
+ // Quest Repeat takes priority. Don't worry, you won't lose password unless
+ // you accept the quest again.
+ if (MONA_TIME <= gettimeparam(GETTIME_DAYOFMONTH)) {
+ find_daddy_quest();
+ }
+
+ // Sagratha is Great B-)
+ npctalkonce any(
+ l("Thanks for finding daddy... I wish he spent more time with me..."),
+ l("Sagratha is great. Why does the strange woman near the Legion building always say that to daddy...?")); // TODO: Polish
+ }
+ else if (getq(ArtisQuests_MonaDad) == 2)
+ {
+ if (check_daddy_quest())
+ {
+ if (!MONA_REPEAT)
+ {
+ inventoryplace WoodenSword, 1;
+ speech 0x0,
+ l("Daddy finally came back home! He grabbed a snack and said he would be returning to the sewers."),
+ l("He did say that I should give you this @@ as a gift. He says you are very skilled and will make good use of his old weapon.",
+ getitemlink(WoodenSword)),
+ l("He has never been the same since mommy went away...");
+ getitem WoodenSword, 1;
+ }
+ else if (MONA_REPEAT == 10)
+ {
+ speech
+ l("Daddy asked me to give you some money as a thank you for looking out for me."),
+ l("I don't want you! I want daddy!");
+ mesc l("*sniff sniff*");
+ emotion E_SAD;
+ Zeny+=1000;
+ }
+ else
+ {
+ inventoryplace TrainingArrow, 100;
+ getitem TrainingArrow, min(MONA_REPEAT*20, 100);
+ }
+ setq(ArtisQuests_MonaDad, 3);
+ MONA_TIME=gettimeparam(GETTIME_DAYOFMONTH)+3;
+ MONA_REPEAT+=1;
+ close;
+ }
+ }
+ else
+ {
+ npctalkonce l("Please find daddy...");
+ }
+
+ emotion E_SAD;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-2-12/_import.txt b/npc/001-2-12/_import.txt
new file mode 100644
index 00000000..fa40eb2b
--- /dev/null
+++ b/npc/001-2-12/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-12: Noble House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-12/_warps.txt",
+"npc/001-2-12/mapflags.txt",
+"npc/001-2-12/oscar.txt",
diff --git a/npc/001-2-12/_warps.txt b/npc/001-2-12/_warps.txt
new file mode 100644
index 00000000..c03a6b0b
--- /dev/null
+++ b/npc/001-2-12/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-12: Noble House warps
+001-2-12,27,27,0 warp #001-2-12_27_27 1,0,001-2-13,27,29
+001-2-12,34,36,0 warp #001-2-12_34_36 0,0,001-1,142,31
+001-2-12,29,28,0 warp #001-2-12_29_28 0,0,001-2-14,25,29
diff --git a/npc/001-2-12/mapflags.txt b/npc/001-2-12/mapflags.txt
new file mode 100644
index 00000000..a84ff938
--- /dev/null
+++ b/npc/001-2-12/mapflags.txt
@@ -0,0 +1 @@
+001-2-12 mapflag town
diff --git a/npc/001-2-12/oscar.txt b/npc/001-2-12/oscar.txt
new file mode 100644
index 00000000..343a012e
--- /dev/null
+++ b/npc/001-2-12/oscar.txt
@@ -0,0 +1,144 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Old man living in the rich hill, can bleach clothes.
+
+001-2-12,38,30,0 script Oscar#001-2-12 NPC_OSCAR,{
+
+ function live_here_alone
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Meh!"),
+ l("This is a harsh word to use, you are never alone in the beautiful place of Artis."),
+ l("Mob is doing its daily noise, nature is singing its sumptuous melody, none is alone.");
+
+ return;
+ }
+
+ function item_is_bleachable
+ {
+ .@item_index = getarg(0);
+ if (.@item_index < 0)
+ return false;
+
+ getinventorylist;
+
+ if (@inventorylist_card1[.@item_index] != 0)
+ {
+ if ((@inventorylist_card1[.@item_index] > YellowCottonDye) ||
+ (@inventorylist_card1[.@item_index] < CrimsonCashmereDye))
+ {
+ return false;
+ }
+ .@is_bleachable = true;
+ }
+ if (@inventorylist_card2[.@item_index] != 0)
+ {
+ if ((@inventorylist_card2[.@item_index] > YellowCottonDye) ||
+ (@inventorylist_card2[.@item_index] < CrimsonCashmereDye))
+ {
+ return false;
+ }
+ .@is_bleachable = true;
+ }
+ if (@inventorylist_card3[.@item_index] != 0)
+ {
+ if ((@inventorylist_card3[.@item_index] > YellowCottonDye) ||
+ (@inventorylist_card3[.@item_index] < CrimsonCashmereDye))
+ {
+ return false;
+ }
+ .@is_bleachable = true;
+ }
+ if (@inventorylist_card4[.@item_index] != 0)
+ {
+ if ((@inventorylist_card4[.@item_index] > YellowCottonDye) ||
+ (@inventorylist_card4[.@item_index] < CrimsonCashmereDye))
+ {
+ return false;
+ }
+ .@is_bleachable = true;
+ }
+
+ return .@is_bleachable;
+ }
+
+ function remove_cards_from_item
+ {
+ .@item_index = -1;
+
+ speech S_FIRST_BLANK_LINE,
+ l("What item would you like to bleach?");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You can drag and drop an item to the NPC window or select an item through your inventory.");
+
+ .@item_index = requestitemindex();
+ if (!item_is_bleachable(.@item_index))
+ {
+ speech S_LAST_NEXT,
+ l("You should know this, an item like this can't be bleached.");
+
+ return;
+ }
+
+ speech S_LAST_NEXT,
+ l("Your mind is set? You will loose the color dye during this process.");
+
+ switch (askyesno())
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ok, let me see..."),
+ l("...");
+
+ failedremovecardsindex .@item_index, 1;
+
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("..."),
+ l("Here it is, clean like a whistle!");
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Is it truly a hard choice to make?");
+ break;
+ }
+
+ return;
+ }
+
+ .@hour = gettime(GETTIME_HOUR);
+ speech S_LAST_NEXT, (.@hour > 6 && .@hour < 18) ? l("Good day to you.") : l("Good evening.");
+
+ do
+ {
+ select
+ l("Could you bleach my clothes?"),
+ l("Do you live here alone?"),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ remove_cards_from_item();
+ break;
+ case 2:
+ live_here_alone();
+ break;
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("I wish you a good time in town.");
+ break;
+ }
+
+ } while (@menu != 3);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-2-13/_import.txt b/npc/001-2-13/_import.txt
new file mode 100644
index 00000000..36eee751
--- /dev/null
+++ b/npc/001-2-13/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-13: First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-13/_savepoints.txt",
+"npc/001-2-13/_warps.txt",
+"npc/001-2-13/mapflags.txt",
diff --git a/npc/001-2-13/_savepoints.txt b/npc/001-2-13/_savepoints.txt
new file mode 100644
index 00000000..fd073ac6
--- /dev/null
+++ b/npc/001-2-13/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-13: First Floor saves
+001-2-13,41,31,0 script #save_001-2-13_41_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-13/_warps.txt b/npc/001-2-13/_warps.txt
new file mode 100644
index 00000000..9400dd8a
--- /dev/null
+++ b/npc/001-2-13/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-13: First Floor warps
+001-2-13,27,30,0 warp #001-2-13_27_30 1,0,001-2-12,27,28
diff --git a/npc/001-2-13/mapflags.txt b/npc/001-2-13/mapflags.txt
new file mode 100644
index 00000000..329eb054
--- /dev/null
+++ b/npc/001-2-13/mapflags.txt
@@ -0,0 +1 @@
+001-2-13 mapflag town
diff --git a/npc/001-2-14/_import.txt b/npc/001-2-14/_import.txt
new file mode 100644
index 00000000..0b4d600c
--- /dev/null
+++ b/npc/001-2-14/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-14: Basement
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-14/_warps.txt",
+"npc/001-2-14/mapflags.txt",
diff --git a/npc/001-2-14/_warps.txt b/npc/001-2-14/_warps.txt
new file mode 100644
index 00000000..4ae630aa
--- /dev/null
+++ b/npc/001-2-14/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-14: Basement warps
+001-2-14,26,27,0 warp #001-2-14_26_27 1,0,001-2-12,30,28
diff --git a/npc/001-2-14/mapflags.txt b/npc/001-2-14/mapflags.txt
new file mode 100644
index 00000000..a84ff938
--- /dev/null
+++ b/npc/001-2-14/mapflags.txt
@@ -0,0 +1 @@
+001-2-12 mapflag town
diff --git a/npc/001-2-15/_import.txt b/npc/001-2-15/_import.txt
new file mode 100644
index 00000000..d4250125
--- /dev/null
+++ b/npc/001-2-15/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-15: Noble House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-15/_savepoints.txt",
+"npc/001-2-15/_warps.txt",
+"npc/001-2-15/mapflags.txt",
diff --git a/npc/001-2-15/_savepoints.txt b/npc/001-2-15/_savepoints.txt
new file mode 100644
index 00000000..cd164505
--- /dev/null
+++ b/npc/001-2-15/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-15: Noble House saves
+001-2-15,27,41,0 script #save_001-2-15_27_41 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-15/_warps.txt b/npc/001-2-15/_warps.txt
new file mode 100644
index 00000000..5704aecc
--- /dev/null
+++ b/npc/001-2-15/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-15: Noble House warps
+001-2-15,34,46,0 warp #001-2-15_34_46 0,0,001-1,132,68
diff --git a/npc/001-2-15/mapflags.txt b/npc/001-2-15/mapflags.txt
new file mode 100644
index 00000000..5ff9ed8d
--- /dev/null
+++ b/npc/001-2-15/mapflags.txt
@@ -0,0 +1 @@
+001-2-15 mapflag town
diff --git a/npc/001-2-16/_import.txt b/npc/001-2-16/_import.txt
new file mode 100644
index 00000000..66b975ca
--- /dev/null
+++ b/npc/001-2-16/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-16: Harbourmaster Lodge
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-16/_warps.txt",
+"npc/001-2-16/mapflags.txt",
diff --git a/npc/001-2-16/_warps.txt b/npc/001-2-16/_warps.txt
new file mode 100644
index 00000000..ba8035ee
--- /dev/null
+++ b/npc/001-2-16/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-16: Harbourmaster Lodge warps
+001-2-16,32,36,0 warp #001-2-16_32_36 0,0,001-1,168,99
+001-2-16,24,29,0 warp #001-2-16_24_29 0,0,001-2-17,35,29
diff --git a/npc/001-2-16/mapflags.txt b/npc/001-2-16/mapflags.txt
new file mode 100644
index 00000000..44cfc0a1
--- /dev/null
+++ b/npc/001-2-16/mapflags.txt
@@ -0,0 +1 @@
+001-2-16 mapflag town
diff --git a/npc/001-2-17/_import.txt b/npc/001-2-17/_import.txt
new file mode 100644
index 00000000..ef22e0df
--- /dev/null
+++ b/npc/001-2-17/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-17: Backroom
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-17/_warps.txt",
+"npc/001-2-17/mapflags.txt",
diff --git a/npc/001-2-17/_warps.txt b/npc/001-2-17/_warps.txt
new file mode 100644
index 00000000..b2f5355e
--- /dev/null
+++ b/npc/001-2-17/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-17: Backroom warps
+001-2-17,36,29,0 warp #001-2-17_36_29 0,0,001-2-16,25,29
diff --git a/npc/001-2-17/mapflags.txt b/npc/001-2-17/mapflags.txt
new file mode 100644
index 00000000..ae59a377
--- /dev/null
+++ b/npc/001-2-17/mapflags.txt
@@ -0,0 +1 @@
+001-2-17 mapflag town
diff --git a/npc/001-2-18/_import.txt b/npc/001-2-18/_import.txt
new file mode 100644
index 00000000..a2930084
--- /dev/null
+++ b/npc/001-2-18/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-18: Docks Warehouse
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-18/_warps.txt",
+"npc/001-2-18/mapflags.txt",
diff --git a/npc/001-2-18/_warps.txt b/npc/001-2-18/_warps.txt
new file mode 100644
index 00000000..e0342239
--- /dev/null
+++ b/npc/001-2-18/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-18: Docks Warehouse warps
+001-2-18,39,36,0 warp #001-2-18_39_36 0,0,001-1,182,75
+001-2-18,39,26,0 warp #001-2-18_39_26 2,0,001-2-42,39,36
diff --git a/npc/001-2-18/mapflags.txt b/npc/001-2-18/mapflags.txt
new file mode 100644
index 00000000..db4e1433
--- /dev/null
+++ b/npc/001-2-18/mapflags.txt
@@ -0,0 +1 @@
+001-2-18 mapflag town
diff --git a/npc/001-2-19/_import.txt b/npc/001-2-19/_import.txt
new file mode 100644
index 00000000..c92d0825
--- /dev/null
+++ b/npc/001-2-19/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-19: Merchant Hall
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-19/_warps.txt",
+"npc/001-2-19/lloyd.txt",
+"npc/001-2-19/mapflags.txt",
diff --git a/npc/001-2-19/_warps.txt b/npc/001-2-19/_warps.txt
new file mode 100644
index 00000000..cb48d355
--- /dev/null
+++ b/npc/001-2-19/_warps.txt
@@ -0,0 +1,51 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-19: Merchant Hall warps
+001-2-19,41,31,0 warp #001-2-19_41_31 0,0,001-1,104,33
+001-2-19,41,24,0 script #001-2-19_41_24_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-25", 29, 30;
+close;
+
+OnUnTouch:
+ doevent "#001-2-19_41_24::OnUnTouch";
+}
+001-2-19,41,24,0 script #001-2-19_41_24 NPC_ARTIS_DOOR_WOOD,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-2-19,33,38,0 warp #001-2-19_33_38 0,0,001-1,101,37
+001-2-19,41,55,0 warp #001-2-19_41_55 0,0,001-2-20,29,27
+001-2-19,41,47,0 script #001-2-19_41_47_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-1", 104, 42;
+close;
+
+OnUnTouch:
+ doevent "#001-2-19_41_47::OnUnTouch";
+}
+001-2-19,41,47,0 script #001-2-19_41_47 NPC_ARTIS_DOOR_WOOD,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
diff --git a/npc/001-2-19/lloyd.txt b/npc/001-2-19/lloyd.txt
new file mode 100644
index 00000000..839f9817
--- /dev/null
+++ b/npc/001-2-19/lloyd.txt
@@ -0,0 +1,249 @@
+// Evol scripts.
+// Authors:
+// gumi
+// Reid
+// Description:
+// Lloyd the banker NPC.
+// Variables:
+// 0 ArtisQuests_Lloyd
+// 1 ArtisQuests_Fexil
+// 2 ArtisQuests_Enora
+// Quest states:
+// 00 -- Never talked
+// 01 -- Registred on the Guild
+// 10 -- not started
+// 11 -- Lloyd warned about the quest
+// 20 -- Default.
+// 21 -- BlackSmith quest delivered.
+// 22 -- Chelios Quest given.
+// 23 -- Chelios Quest done.
+
+001-2-19,31,25,0 script Lloyd the Banker NPC_LLOYD,{
+
+ function enora_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Black iron... That is a very specific request that you have for me!"),
+ l("Let me check in my inventory book..."),
+ l("..."),
+ l("Yes, I have some! \"5x Black Iron Ingots\""),
+ l("Is this for you or somebody else? Because you need to be registered to obtain these materials.");
+
+ switch (selectd(ArtisQuests_Enora,
+ l("This is for my own use."),
+ l("Chelios asked me to get it.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE,
+ l("This is your first time asking for something, you won't pay this time, take it as a sign of good faith!"),
+ l("If you need something in the future, do not hesitate to pass by here, our stock is full of boxes collecting dust.");
+ emotion E_WINK;
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("Chelios... He is part of the Blacksmith House, is he not?"),
+ l("Since Don settled in Artis he and his band refused to register to the Merchant Guild."),
+ l("I will close an eye for once, but only because it's your first time asking for something!"),
+ l("Sometimes a good merchant needs to reach out first. It's on the house, give Chelios my regards!");
+ emotion E_WINK;
+ break;
+ }
+ setq ArtisQuests_Enora, 3;
+
+ return;
+ }
+
+ function explain_guild {
+ speech S_LAST_NEXT,
+ l("The guild is in charge of the commerce regularization throughout Artis and its surroundings."),
+ l("With the help of the town hall and the Legion of Aemil we organize some auction and we help local merchants to launch their businesses."),
+ l("We also feature some services like a storage and a bank for members."),
+ l("Registration is open to everybody, but newcomers need to pay a fee for all of the paperwork.");
+
+ narrator S_FIRST_BLANK_LINE,
+ l("The bank and item storage is shared between all characters within a same account."),
+ l("With it, you can safely move items and funds between your characters."),
+ l("To move between characters that are on different accounts, you have to use the Trade function.");
+ return;
+ }
+
+ function first_visit {
+ speech S_LAST_NEXT,
+ l("Welcome!"),
+ l("My name is Lloyd, I am a representative of the Merchant Guild of Artis.");
+
+ selectd(l("My name is @@...", strcharinfo(0)));
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("\"@@\", I like this name!", strcharinfo(0)),
+ l("Oh, wait a second...");
+ narrator S_LAST_NEXT,
+ l("Lloyd is searching something in his book.");
+ speech S_LAST_NEXT,
+ l("I see."),
+ l("You are new around here, right?");
+
+ if (selectd(l("How do you know?"), l("Yes I am.")) == 1)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh, it is simple. I have on this book the names of every citizen of Artis and its surroundings."),
+ l("And I have no mention of a so called \"@@\" on it!", strcharinfo(0));
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I knew it!");
+ }
+
+ speech S_LAST_NEXT,
+ l("Let me explain to you what the Merchant Guild is for.");
+
+ explain_guild;
+ next;
+
+ .@price = 500;
+ speech S_LAST_NEXT,
+ l("The fee is of @@ E. So, do you want to register?", .@price);
+
+ switch (selectd(l("Yes."),
+ l("I don't have the time now.")))
+ {
+ case 1:
+ if (Zeny < .@price)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You do not seem to have enough money, come back later!");
+ }
+ else
+ {
+ Zeny -= .@price;
+ setq ArtisQuests_Lloyd, 1;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Perfect!"),
+ l("I wrote your name on the book, you are now free to use the storage and bank services.");
+ }
+ break;
+ case 2:
+ break;
+ }
+
+ return;
+ }
+
+ function paper_to_deliver {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Now that you bring up that topic, that reminds me of something..."),
+ l("Earlier today there was this young seller named Fexil that passed by here."),
+ l("He asked to lend some money and a place to open his store, I think that he asked for a place on the merchant squares on the south-west of the city..."),
+ l("Anyway, he forgot his permit when he left the building."),
+ l("Could you bring it to him?");
+
+ do
+ {
+ .@q = selectd(ArtisQuests_Fexil,
+ l("Ok, I will bring it to him."),
+ l("I need more information first."),
+ l("I don't have the time."));
+ switch (.@q)
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thank you for this!");
+ setq ArtisQuests_Fexil, 1;
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You should look for a seller named Fexil around the merchant square."),
+ l("Ask other merchants, they might know where he is.");
+ break;
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("No problem, come back later if you changed your mind!");
+ break;
+ }
+ } while (.@q == 2);
+ }
+
+ if (getq(ArtisQuests_Lloyd) == 0)
+ {
+ first_visit;
+
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ speech S_LAST_NEXT,
+ l("Welcome to the Merchant Guild of Artis!"),
+ l("What do you want today?");
+
+ do
+ {
+ .@enora = getq(ArtisQuests_Enora);
+
+ selectd
+ rif(.@enora == 2, l("I'm looking for some black iron ingots.")),
+ l("I would like to store some items."),
+ l("I would like to perform money transactions."),
+ l("What is this guild for?"),
+ l("Does the guild has any work for me right now?"),
+ l("Bye.");
+
+ switch (@menu)
+ {
+ case 1:
+ enora_quest;
+ break;
+ case 2:
+ closeclientdialog();
+ openstorage();
+ close;
+ break;
+ case 3:
+ MerchantGuild_Bank();
+ break;
+ case 4:
+ mes "";
+ explain_guild;
+ break;
+ case 5:
+ if (getq(ArtisQuests_Fexil) >= 1)
+ {
+ MerchantGuild_Quests(.bankid);
+ continue;
+ }
+
+ paper_to_deliver();
+
+ continue;
+ }
+ if (@menu != 6)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT | S_NO_NPC_NAME,
+ l("Something else?");
+ }
+ } while (@menu != 6);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .quest_debug = ArtisQuests_Lloyd;
+ .distance = 4;
+
+ // Bank configuration
+ array_push($@BANK_NAME$, .name$);
+ array_push($@BANK_TOWN$, "Artis");
+ .bankid = getarraysize($@BANK_NAME$)-1;
+ end;
+}
+
+function script FixBankVault {
+ if (#MerchantBank)
+ {
+ BankVault += max(0, #MerchantBank);
+ #MerchantBank = 0;
+ }
+ return;
+}
+
diff --git a/npc/001-2-19/mapflags.txt b/npc/001-2-19/mapflags.txt
new file mode 100644
index 00000000..f083b6eb
--- /dev/null
+++ b/npc/001-2-19/mapflags.txt
@@ -0,0 +1 @@
+001-2-19 mapflag town
diff --git a/npc/001-2-2/_import.txt b/npc/001-2-2/_import.txt
new file mode 100644
index 00000000..7d11248e
--- /dev/null
+++ b/npc/001-2-2/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-2: Moon's House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-2/_warps.txt",
+"npc/001-2-2/mapflags.txt",
+"npc/001-2-2/moon.txt",
diff --git a/npc/001-2-2/_warps.txt b/npc/001-2-2/_warps.txt
new file mode 100644
index 00000000..f28c931d
--- /dev/null
+++ b/npc/001-2-2/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-2: Moon's House warps
+001-2-2,38,39,0 warp #001-2-2_38_39 0,0,001-1,70,78
+001-2-2,27,29,0 warp #001-2-2_27_29 2,0,001-2-3,27,30
diff --git a/npc/001-2-2/mapflags.txt b/npc/001-2-2/mapflags.txt
new file mode 100644
index 00000000..ff5a8f27
--- /dev/null
+++ b/npc/001-2-2/mapflags.txt
@@ -0,0 +1 @@
+001-2-2 mapflag town
diff --git a/npc/001-2-2/moon.txt b/npc/001-2-2/moon.txt
new file mode 100644
index 00000000..081b66ae
--- /dev/null
+++ b/npc/001-2-2/moon.txt
@@ -0,0 +1,215 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// Moon, main NPC for the urchin quest.
+// Variables:
+// ArtisQuests_Urchin - quest var
+// Quest stages:
+// 0 - not started
+// 1 - started, searching for Croc Claws
+// 2 - quest finished
+
+001-2-2,33,32,0 script Moon#001-2-2 NPC_ELVEN_FEMALE,3,3,{
+
+ function SayRandomGreeting {
+ .@q = getq(ArtisQuests_Urchin);
+ .@tick = gettimetick(1);
+ if (.@tick > @ArtisQuests_Urchin_MoonMsgTick + 12)
+ {
+ setarray .messages$[0], l("Ouch!"), l("It hurts so bad!"),
+ l("Help me!"), l("Hurry up!"),
+ l("I can't wait all day!"),
+ l("I need more Croc Claws."),
+ l("What a relief."),
+ l("No more pain, thanks to you."),
+ l("I can walk again!");
+ setarray .msg_first[0], 0, 3, 6;
+ setarray .msg_last[0], 2, 5, 8;
+ .@r = rand(.msg_first[.@q],.msg_last[.@q]);
+ .@msg$ = .messages$[.@r];
+ npctalk3 .@msg$;
+ @ArtisQuests_Urchin_MoonMsgTick = .@tick;
+ }
+ }
+
+ function CheckCrowClaw {
+ if (getq(ArtisQuests_Urchin) != 1)
+ return -1;
+
+ mes "";
+ mesn;
+ if (countitem("CrocClaw") > 0)
+ {
+ delitem "CrocClaw", 1;
+ if (rand(8) == 7) // the lucky 7
+ {
+ mesq l("Yay, it worked! I removed a spike.");
+ ArtisQuests_Urchin_ULeft--;
+ next;
+ if (!ArtisQuests_Urchin_ULeft)
+ {
+ mesq l("It seems I got them all!");
+ next;
+ mesq l("Here is your reward.");
+ setq ArtisQuests_Urchin, 2;
+ quest_xp(.maxLevel, 1500);
+ quest_jxp(.maxLevel, 100);
+ close2;
+ return 1;
+ }
+ else
+ {
+ mesq l("But I still have some spikes left in my foot.");
+ next;
+ return 0;
+ }
+ }
+ else
+ {
+ mesq l("This one is useless! Give me another @@.", getitemlink("CrocClaw"));
+ next;
+ return 0;
+ }
+ }
+ else
+ {
+ mesq l("You don't have any @@, are you mocking me?", getitemlink("CrocClaw"));
+ close2;
+ return 1;
+ }
+ }
+
+ stopnpctimer;
+
+ .@q = getq(ArtisQuests_Urchin);
+ if (.@q < 2)
+ {
+ mesn "Narrator";
+ mesc(l("You see a young elven girl, with a strong sense of pain in her face."), 9);
+ next;
+ }
+ else
+ {
+ mesn;
+ mesq l("I appreciate your help, @@.", strcharinfo(0));
+ goto L_Close;
+ }
+ if (.@q == 1) goto L_QuestStarted;
+
+L_Story:
+ select
+ l("Hi, can I help you somehow?");
+ mes "";
+ mesn;
+ mesq l("That would be great!");
+ next;
+ mesq l("Hi, my name is Moon. This morning I went for a walk on the beach.");
+ next;
+ mesq l("Walking barefoot, feeling the hot sand with my feet, daydreaming... I like such things, you know.");
+ next;
+ mesq l("I didn't notice that a Pikpik was in my way, and when I stepped on it, my foot was full of spikes.");
+ next;
+ mesq l("Luckily the beach is nearby, and somehow I made my way home.");
+ next;
+ mesq l("Please bring me @@s so I can pull out these spikes from my foot.", getitemlink("CrocClaw"));
+ next;
+
+ switch (select(l("Stay here, I will be back as soon as I have some."),
+ l("Maybe next time.")))
+ {
+ case 1:
+ setq ArtisQuests_Urchin, 1;
+ mes "";
+ mesn;
+ mesq l("It really hurts, please hurry!");
+
+ ArtisQuests_Urchin_ULeft = rand(3,5);
+
+ next;
+ goto L_Where;
+ break;
+ case 2:
+ mes "";
+ mesn "Narrator";
+ mesc(l("The girl looks desperate."),9);
+ }
+ goto L_Close;
+
+L_QuestStarted:
+ mesn;
+ mesq l("Do you have @@s for me?", getitemlink("CrocClaw"));
+ next;
+
+ select
+ l("Check out this one."),
+ l("I should put more effort into this."),
+ l("Where can I find some Croc Claws?");
+
+ switch (@menu)
+ {
+ case 1:
+ .@MustRepeat = CheckCrowClaw;
+ if (!.@MustRepeat)
+ goto L_CheckLoop;
+ goto L_Close;
+ case 2:
+ mes "";
+ mesn;
+ mesq l("It really hurts, please hurry!");
+ goto L_Close;
+ case 3:
+ mes "";
+ mesn;
+ goto L_Where;
+ }
+
+L_CheckLoop:
+ while (!.@MustRepeat)
+ {
+ switch (select(l("Here is another one."),
+ l("I must leave to get more.")))
+ {
+ case 1:
+ .@MustRepeat = CheckCrowClaw;
+ break;
+ case 2:
+ goto L_Close;
+ }
+ }
+ goto L_Close;
+
+L_Where:
+ mesq l("You can find some Crocs on the beach, you could look up at the one after the gate, on top of this city.");
+
+ goto L_Close;
+
+L_Close:
+ initnpctimer;
+ close;
+
+OnTimer1000:
+ domovestep;
+
+OnTouch:
+ SayRandomGreeting;
+ end;
+
+OnHour00:
+ if (playerattached())
+ @ArtisQuests_Urchin_MoonMsgTick = 0;
+ end;
+
+OnInit:
+ .distance = 3;
+ .maxLevel = getmonsterinfo(Croc, MOB_LV) + 10;
+ initpath "move", 41, 30,
+ "dir", DOWN, 0,
+ "wait", 2, 0,
+ "move", 33, 32,
+ "dir", DOWN, 0,
+ "wait", 10, 0;
+ initialmove;
+ initnpctimer;
+}
diff --git a/npc/001-2-20/_import.txt b/npc/001-2-20/_import.txt
new file mode 100644
index 00000000..5929d241
--- /dev/null
+++ b/npc/001-2-20/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-20: Backroom
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-20/_warps.txt",
+"npc/001-2-20/mapflags.txt",
diff --git a/npc/001-2-20/_warps.txt b/npc/001-2-20/_warps.txt
new file mode 100644
index 00000000..a032fa4d
--- /dev/null
+++ b/npc/001-2-20/_warps.txt
@@ -0,0 +1,26 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-20: Backroom warps
+001-2-20,33,35,0 warp #001-2-20_33_35 0,0,001-1,107,50
+001-2-20,29,25,0 script #001-2-20_29_25_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-19", 41, 54;
+close;
+
+OnUnTouch:
+ doevent "#001-2-20_29_25::OnUnTouch";
+}
+001-2-20,29,25,0 script #001-2-20_29_25 NPC_ARTIS_DOOR_WOOD,2,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
diff --git a/npc/001-2-20/mapflags.txt b/npc/001-2-20/mapflags.txt
new file mode 100644
index 00000000..499fd5a6
--- /dev/null
+++ b/npc/001-2-20/mapflags.txt
@@ -0,0 +1 @@
+001-2-20 mapflag town
diff --git a/npc/001-2-21/_import.txt b/npc/001-2-21/_import.txt
new file mode 100644
index 00000000..b0f7a5a1
--- /dev/null
+++ b/npc/001-2-21/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-21: First Deck
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-21/_warps.txt",
+"npc/001-2-21/julia.txt",
+"npc/001-2-21/mapflags.txt",
+"npc/001-2-21/note.txt",
diff --git a/npc/001-2-21/_warps.txt b/npc/001-2-21/_warps.txt
new file mode 100644
index 00000000..01f70e01
--- /dev/null
+++ b/npc/001-2-21/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-21: First Deck warps
+001-2-21,19,28,0 warp #001-2-21_19_28 0,0,001-1,193,109
+001-2-21,33,28,0 warp #001-2-21_33_28 0,0,001-2-24,20,27
+001-2-21,31,25,0 warp #001-2-21_31_25 0,0,001-2-22,72,29
diff --git a/npc/001-2-21/julia.txt b/npc/001-2-21/julia.txt
new file mode 100644
index 00000000..b275d910
--- /dev/null
+++ b/npc/001-2-21/julia.txt
@@ -0,0 +1,140 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Qwerty Dragon
+// Reid
+// Vasily_Makarov
+// Description:
+// Allows to change language.
+
+001-2-21,27,24,0 script Julia#Artis NPC_JULIA,{
+ mesn;
+ mesq l("Hello dear!");
+ next;
+ mesq l("What do you want today?");
+ next;
+
+ .@s$ = l("I don't want to change my language, sorry.");
+
+L_Menu:
+ .@enora = getq(ArtisQuests_Enora);
+
+ menu
+ rif(getskilllv(1) < 6, l("Something is wrong with me, I can't smile nor sit.")), L_BasicSkill,
+ rif(.@enora == 0, l("Where should I go?")), L_Enora,
+ l("I made a mistake, I would like to change my language."), L_ChooseLang,
+ l("Is it possible to go back to Drasil Island?"), L_Island,
+ l("Could you explain to me where I am?"), L_WhereIam,
+ l("What happened to me?"), L_What,
+ l("Can I read the rules again?"), L_Rules,
+ l("Nothing, sorry."), L_Quit;
+
+L_YNMenu:
+ menu
+ l("Yes, I do."), L_Menu,
+ l("No, none."), L_Quit;
+
+L_NoChanges:
+ mes "";
+ mesn;
+ mesq l("No problem, do you have any other questions for me?");
+ next;
+
+ goto L_YNMenu;
+
+L_ChooseLang:
+ mes "";
+ mesn;
+ mesq l("Of course! Tell me which language you speak and I will change the note on the ship board list.");
+ next;
+
+ asklanguage(LANG_IN_SHIP);
+
+ mes "";
+ mesn;
+ mesq l("Ok, done.");
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+
+ goto L_Menu;
+
+L_WhereIam:
+ mes "";
+ mesn;
+ mesq l("You're on La Johanne, a merchant ship.");
+ next;
+ mesq l("We arrived this morning at the port of Artis, I already warned the Legion of Aemil concerning your issue.");
+ next;
+ mesq l("Somebody is waiting for you outside!");
+ next;
+ mesq l("Like the rest of the crew, you are welcome to come and rest here at anytime during your journey on Artis.");
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+
+ goto L_YNMenu;
+
+L_What:
+ mes "";
+ mesn;
+ mesq l("We thought that you could help us understand this, all we know is that we found you cast in the sea, adrift on your raft.");
+ next;
+ mesq l("You were in bad shape, you should be happy we found you before the sea killed you.");
+ next;
+ mesq l("Oh, and there was this inscription on your raft. It represents the Legion of Aemil, the largest and biggest guild of the whole new world. Does that make you remember anything, anything at all?");
+ next;
+
+ select
+ l("Sorry, but I can't tell you anything about that."),
+ l("Nothing, sorry.");
+
+ goto L_NoChanges;
+
+L_Rules:
+ mes "";
+ mesn;
+ mesq l("Of course, they are on the left wall. Go have a look at them.");
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+
+ goto L_YNMenu;
+
+L_BasicSkill:
+ mes "";
+ mesn;
+ mesq l("Let me check into it...");
+ next;
+ adddefaultskills;
+ mesq l("Here you go, everything is fixed.");
+ emotion E_HAPPY;
+ next;
+ mesq l("Do you have any other questions for me?");
+ next;
+
+ goto L_YNMenu;
+
+L_Enora:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Enora, from the Legion of Aemil, has been warned that you were aboard."),
+ l("She is waiting for you on the dock."),
+ l("Do you have any other questions for me?");
+
+ goto L_YNMenu;
+
+L_Quit:
+ goodbye;
+
+L_Island:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Of course, as a fully-fledged crew member you can decide of the destination of La Johanne directly with Nard.");
+ l("Do you have any other questions for me?");
+ emotion E_HAPPY;
+
+ goto L_YNMenu;
+
+OnInit:
+ .distance = 10;
+ end;
+}
diff --git a/npc/001-2-21/mapflags.txt b/npc/001-2-21/mapflags.txt
new file mode 100644
index 00000000..a3f0260b
--- /dev/null
+++ b/npc/001-2-21/mapflags.txt
@@ -0,0 +1 @@
+001-2-21 mapflag town
diff --git a/npc/001-2-21/note.txt b/npc/001-2-21/note.txt
new file mode 100644
index 00000000..cd1764ed
--- /dev/null
+++ b/npc/001-2-21/note.txt
@@ -0,0 +1,27 @@
+// Evol scripts.
+// Authors:
+// gumi
+// Qwerty Dragon
+// Reid
+// WildX
+// Description:
+// A small note presenting the 6 main rules of Evol Online.
+
+001-2-21,29,25,0 script Note#Artis NPC_PAPER_NOTE,{
+ narrator S_LAST_NEXT,
+ l("There is a paper with some rules written on it.");
+
+ GameRules 8 | 4;
+
+ narrator S_NO_NPC_NAME,
+ l("Following these lines are some other writings on this paper."),
+ l("Do not give the password of your room to anybody! Keep it secret and try not to use the same one in any other room in the future. - Julia"),
+ l("Does anyone know a good place to hang out in Esperia? - M. Arpan"),
+ l("Other things are written but are not legible anymore.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-22/_import.txt b/npc/001-2-22/_import.txt
new file mode 100644
index 00000000..96490c74
--- /dev/null
+++ b/npc/001-2-22/_import.txt
@@ -0,0 +1,13 @@
+// Map 001-2-22: Second Deck
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-22/_mobs.txt",
+"npc/001-2-22/_savepoints.txt",
+"npc/001-2-22/_warps.txt",
+"npc/001-2-22/alige.txt",
+"npc/001-2-22/chefgado.txt",
+"npc/001-2-22/chest.txt",
+"npc/001-2-22/hammock.txt",
+"npc/001-2-22/knife.txt",
+"npc/001-2-22/mapflags.txt",
+"npc/001-2-22/note.txt",
+"npc/001-2-22/peter.txt",
diff --git a/npc/001-2-22/_mobs.txt b/npc/001-2-22/_mobs.txt
new file mode 100644
index 00000000..a2164e45
--- /dev/null
+++ b/npc/001-2-22/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-22: Second Deck mobs
+001-2-22,52,32,21,9 monster Piou 1002,3,30000,20000
diff --git a/npc/001-2-22/_savepoints.txt b/npc/001-2-22/_savepoints.txt
new file mode 100644
index 00000000..b4a5c1ba
--- /dev/null
+++ b/npc/001-2-22/_savepoints.txt
@@ -0,0 +1,67 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-22: Second Deck saves
+001-2-22,40,37,0 script #save_001-2-22_40_37 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-22,46,37,0 script #save_001-2-22_46_37 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-22,55,40,0 script #save_001-2-22_55_40 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-22,50,38,0 script #save_001-2-22_50_38 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-22,53,38,0 script #save_001-2-22_53_38 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-22/_warps.txt b/npc/001-2-22/_warps.txt
new file mode 100644
index 00000000..8fcdb2c3
--- /dev/null
+++ b/npc/001-2-22/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-22: Second Deck warps
+001-2-22,72,30,0 warp #001-2-22_72_30 0,0,001-2-21,31,26
diff --git a/npc/001-2-22/alige.txt b/npc/001-2-22/alige.txt
new file mode 100644
index 00000000..4f4fab9d
--- /dev/null
+++ b/npc/001-2-22/alige.txt
@@ -0,0 +1,325 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Alige
+// Qwerty Dragon
+// Reid
+// Vasily_Makarov
+// Description:
+// Hidden in a ship's hole.
+// 2 bits array:
+// ShipQuests
+// Variable:
+// ShipQuests_Alige
+// Values:
+// 0 Never talk.
+// 1 First talk.
+// 2 Accept the task.
+// 3 Bring first food.
+
+001-2-22,43,32,0 script AligeTrigger#Artis NPC_HIDDEN,1,1,{
+
+OnTouch:
+ if (getareausers() <= 1)
+ {
+ setnpcdir "Alige#Artis", 2;
+ stopnpctimer;
+ initnpctimer;
+ }
+
+ if (getq(ShipQuests_Alige) > 0) close;
+ doevent "Alige#Artis::OnFirstEncounter";
+
+ close;
+
+OnUnTouch:
+ if (getareausers() == 0)
+ {
+ setnpcdir "Alige#Artis", 4;
+ stopnpctimer;
+ initnpctimer;
+ }
+ close;
+
+OnTimer190:
+ stopnpctimer;
+
+ if (getnpcdir("Alige#Artis") == 2) setnpcdir "Alige#Artis", 6;
+ if (getnpcdir("Alige#Artis") == 4) setnpcdir "Alige#Artis", 8;
+
+ end;
+}
+
+001-2-22,43,31,0 script Alige#Artis NPC_ALIGE,{
+ .@q = getq(ShipQuests_Alige);
+ if (.@q > 1) goto L_AskForFood;
+
+ goto OnFirstEncounter;
+
+OnFirstEncounter:
+ setq ShipQuests_Alige, 1;
+
+ setcamnpc;
+ mesn "Hidden Person";
+ mesq l("Hey, psst! You're not a sailor, right?");
+ next;
+ restorecam;
+
+ menu
+ l("I am, who are you?"), -,
+ l("Indeed, I am not."), L_NeedHelp;
+
+ mes "";
+ mesn "Narrator";
+ mesc(l("The stowaway doesn't answer."), 9);
+
+ close;
+
+L_NeedHelp:
+ setcamnpc;
+ mes "";
+ mesn "Hidden Person";
+ mesq l("Good, good... Hey, could you help me please? I beg you, please, pleeeease...");
+ next;
+ restorecam;
+
+ menu
+ l("Why not, but who are you, and what kind of help do you need?"), L_CanHelp;
+ l("Sorry but I have no time for this."), -;
+
+ closeclientdialog;
+ close;
+
+L_CanHelp:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("My name is Alige, I've been hiding here for weeks. All I have to eat are these berries... berries... berries...");
+ next;
+ mesq l("I'm losing my mind here, I need something else to eat!");
+ next;
+ mesq l("Could you please bring me something which isn't a berry, and I'm not big on vegetables either. I need proteins!");
+ next;
+ restorecam;
+
+ menu
+ l("Sure, but what will you give me in exchange?"), L_AboutReward,
+ l("Why don't you come out?"), -;
+
+L_ExplainHiding:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("No, I can't. I won't! All I wanted was to travel across the seas for fun, growl... sniff. And in this hole in the floor, as you can see, I have lots of fun.");
+ next;
+ mesq l("Oh... um... actually... all I wanted was to get to Artis. Err... but I didn't, uhm... have enough money to pay for the ferry!");
+ next;
+ mesq l("Please don't tell people you saw me. I don't want to be decapitated or get thrown into the sea as food for sharks, or get my hair mussed!");
+ next;
+ restorecam;
+
+ if (getq(ShipQuests_Alige) == 2) goto L_SoAskForFood;
+ goto L_Accept;
+
+L_AboutReward:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("I'll share my berries with you if you help me.");
+ next;
+ restorecam;
+
+L_Accept:
+ menu
+ l("Understood, I will help you."), L_FirstAccepted,
+ l("We arrived in Artis today."), L_Artis,
+ l("I think I should report you to the crew members."), -;
+
+ setcamnpc;
+ mesq l("Growl, sniff, grr! You'd better not tell anyone you saw me!");
+
+ close;
+
+L_Artis:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Of course, so why do I still see open sea from the porthole?");
+ next;
+ mesq l("I wonder who is in delarium now...");
+ next;
+ mesq l("But hey, back to me. Remember my mentioning that I'm hun...grrr...eee!");
+ next;
+ restorecam;
+
+ if (.@q == 2) goto L_SoAskForFood;
+ goto L_Accept;
+
+L_FirstAccepted:
+ if (getq(ShipQuests_Alige) >= 2) goto L_Accepted;
+ setq ShipQuests_Alige, 2;
+
+ goto L_Accepted;
+
+L_Accepted:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Great, what food do you have for me today?");
+ next;
+ restorecam;
+
+L_GiveFood:
+ mes "";
+
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+ .@id = requestitem();
+ if (.@id <= 0) goto L_Quit; // Quit message.
+ if (countitem(.@id) == 0) goto L_Quit; // If don't have the food
+
+ if (array_find(.vegetables, .@id) >= 0) goto L_NoReward; // In case of wrong food.
+ if (array_find(.poisonable, .@id) >= 0) goto L_Poison; // In case of poisoned food (or food with effects).
+ if (.@id == Piberries) goto L_NoMore; // In case of Piberries.
+ if (.@id == RedPlushWine) goto L_Drunk; // In case of Alcohol.
+
+ // Default message for non food
+ if (array_find(.commonfood, .@id) == -1) goto L_NoFood;
+
+ inventoryplace Piberries, 3;
+ delitem .@id, 1;
+
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Thank you so much! Here, have some of my berries.");
+
+ setq ShipQuests_Alige, 3;
+ getitem Piberries, rand(1, 3);
+ next;
+
+ goto L_ReturnMenu;
+
+L_NoReward:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("You don't expect me to eat that, do you? Give me something else!");
+ next;
+ restorecam;
+
+ goto L_GiveFood;
+
+L_Drunk:
+ setcamnpc;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I asked for food but... *hips* Ah, that'll do!");
+ restorecam;
+
+ goto L_GiveFood;
+
+L_NoFood:
+ setcamnpc;
+ // We must first determine if it is at least edible (IT_HEALING)
+ if (getiteminfo(.@id, ITEMINFO_TYPE) == IT_HEALING)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That looks too exotic for me to eat!");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That doesn't looks edible to me!");
+ }
+ restorecam;
+
+ goto L_GiveFood;
+
+L_ReturnMenu:
+ setcamnpc;
+ mesq l("Do you have anything else for me?");
+ next;
+ restorecam;
+
+ goto L_GiveFood;
+
+L_NoMore:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Grr, don't give me more berries! I don't want them, stupid berries, stupid... Stupid... Stupid!");
+ next;
+
+ goto L_ReturnMenu;
+
+L_Poison:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Don't try to poison me! I know what that does!");
+ next;
+ restorecam;
+ goto L_ReturnMenu;
+
+L_SoAskForFood:
+ setcamnpc;
+ mesn;
+ mesq l("So, do you have anything for me today?");
+ next;
+ restorecam;
+ goto L_IntroMenu;
+
+L_AskForFood:
+ setcamnpc;
+ mesn;
+ mesq l("Do you have anything for me today?");
+ next;
+ restorecam;
+
+L_IntroMenu:
+ menu
+ l("Yes."), L_GiveFood,
+ l("Where can I find some food?"), L_FindFood,
+ l("Why are you hiding?") + " " + l("Why don't you come out?"), L_ExplainHiding,
+ l("We arrived in Artis today."), L_Artis,
+ l("I think I should report you to the crew members."), -;
+
+ setcamnpc;
+ mesq l("Growl, sniff, grr! You'd better not tell anyone you saw me!");
+
+ close;
+
+L_FindFood:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("There are some flying yellow plushes around you. They're called pious. Getting a roasted leg of one of them would be perfect.");
+ next;
+ mesq l("I'd like to catch one of them, but they fly away when I try.");
+ next;
+ mesq l("Walking around a bit, it'll be easy for you to catch one, I bet. Impale one of them for me please.");
+ next;
+ restorecam;
+ mesn "Narrator";
+ mesc(l("You can attack a monster by clicking on it, or from your keyboard you can press the 'A' key to select the monster followed by 'Ctrl' to attack it."), 9);
+ next;
+ mesc(l("Once the monster is dead, click on the dropped items to add them to your inventory. You can also use the 'Z' key to claim the drops."), 9);
+
+ close;
+
+L_Quit:
+ setcamnpc;
+ mes "";
+ mesn;
+ mesq l("Too bad... Come back when you'll have some nice food for me. Growl... grumble... grumble.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+
+ // Array of foods (remember to update in 000-2-1 as well)
+ setarray .commonfood, Bread, Fungus, Cheese, PiouLegs, Aquada, HalfCroconut, Plushroom, PumpkinJuice, Manana, Curshroom, Carrot, CarpSandwich, PioulegSandwich;
+ setarray .vegetables, Acorn, LettuceLeaf, Croconut, MananaSandwich;
+ setarray .poisonable, SeaDrops, PinkBlobime, PumpkinSeeds, UrchinMeat, EasterEgg;
+ end;
+}
diff --git a/npc/001-2-22/chefgado.txt b/npc/001-2-22/chefgado.txt
new file mode 100644
index 00000000..ae95d408
--- /dev/null
+++ b/npc/001-2-22/chefgado.txt
@@ -0,0 +1,112 @@
+// Evol scripts.
+// Authors:
+// Hal9000
+// Qwerty Dragon
+// Reid
+// Description:
+// La Johanne Chef.
+
+001-2-22,27,28,0 script Chef Gado#Artis NPC_CHEF_GADO,{
+ function foodQuest;
+
+ .@r = rand(3);
+ if (.@r == 0) npctalk3 l("What are you doing in my kitchen?! Get out, it's not a place for kids!");
+ if (.@r == 1) npctalk3 l("Where is the damn salt?! Give me the salt, I know you have it!");
+ if (.@r == 2) npctalk3 l("Are you going to stand here all day long? Do the dishes or go away.");
+
+ if (getq(General_SmearedHands) < 3)
+ foodQuest();
+ close;
+
+function foodQuest {
+ .@q=getq(General_SmearedHands);
+ mesc l("%s seems busy as usual.", l("Chef Gado"));
+ select
+ l("I'll get moving, sorry!"),
+ //rif(.@r == 1 && countitem(Salt), l("Offer him the salt")),
+ l("Can you teach me cooking?");
+ mes "";
+ if (@menu == 1)
+ return;
+ // FOOD QUEST: BEGIN
+ .@ally=(getq(ShipQuests_ChefGado) == 4); // TRUE if you helped Gado
+ mesn;
+ mesq (.@ally ? l("I suppose I could. You helped me, after all.") : l("Why should I help you, traitor?"));
+ next;
+ // Empty Bowl needed
+ if (!countitem(EmptyBowl)) {
+ mesn;
+ mesq l("Anyway: First, you'll need an %s. %s", getitemlink(EmptyBowl),
+ (.@ally ? l("Cannot get one here in Artis, though. Well, if you travel far enough...") : l("Stop wasting my time!")));
+ return;
+ }
+ // Recipe Book needed
+ if (!countitem(RecipeBook)) {
+ mesn;
+ mesq l("Anyway: First, you'll need a %s. You cannot cook without that. So go find one!", getitemlink(RecipeBook));
+ next;
+ mesn;
+ mesq l("These books are annoyingly expensive, but maybe you have luck elsewhere. I'm sure some housewife could give you one for helping her husband...");
+ next;
+ mesn;
+ mesq l("That's how I got mine, anyway.");
+ next;
+ mesn;
+ mesq l("Some nice lady called Ya... Micksha? No, it was not Yamicksha... For the life of me, I can't remember...");
+ // FIXME: I'm ignoring that unpractical plot in favor of clarity
+ return;
+ }
+
+ // Quest Loop
+ if (.@q == 0) {
+ mesn;
+ mesq l("You got a bowl, I see. You won't be finding another one, so be careful with that.");
+ next;
+ // Will only learn Sailor Stew Recipe if helped Gado instead Julia
+ if (.@ally) {
+ mesn;
+ mesq l("Now, watch and learn: The Sailor Stew Recipe!");
+ mesc l("Learned %s recipe!", getitemlink(SailorStew)), 2;
+ RECIPES[CraftSailorStew]=true;
+ next;
+ } else if (!RECIPES[CraftSailorStew]) {
+ // They requested for a neutral approach because Julia
+ mesn;
+ mesq l("I will teach you %s... But for you, it will be %s E.",
+ getitemlink(SailorStew), format_number(5000));
+ if (Zeny < 5000)
+ return;
+ next;
+ mesc l("Pay Chef Gado the gold?");
+ if (askyesno() == ASK_NO || Zeny < 5000)
+ return;
+ mesn;
+ mesq l("Now, watch and learn: The Sailor Stew Recipe!");
+ mesc l("Learned %s recipe!", getitemlink(SailorStew)), 2;
+ RECIPES[CraftSailorStew]=true;
+ Zeny-=5000;
+ next;
+ }
+ setq General_SmearedHands, 1;
+ .@q = 1;
+ mesn;
+ mesq l("Anyway, for the recipe, just add a few carps, carrots, manana, and roasted acorn in this order.");
+ next;
+ }
+ if (.@q == 1 || .@q == 2) {
+ mesn;
+ mesq l("Now, your next task is: I've heard rumors... About some delicious food, like %s...", getitemlink(any(BarbecuePlate, VeggiePlate)));
+ next;
+ mesn;
+ mesq l("They're related to Mouboos, but Artis cuisine is the worst. Go find the recipes!!");
+ next;
+ }
+ mesn;
+ mesq l("Get moving!");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/001-2-22/chest.txt b/npc/001-2-22/chest.txt
new file mode 100644
index 00000000..69e8a8af
--- /dev/null
+++ b/npc/001-2-22/chest.txt
@@ -0,0 +1,49 @@
+// Evol scripts.
+// Authors:
+// 4144
+// gumi
+// Reid
+// Description:
+// A box with clothes for new players.
+
+001-2-22,51,37,0 script Chest#Artis NPC_CHEST_BIG,2,4,{
+
+ if (.busy == false)
+ {
+ specialeffect(.dir == 0 ? 24 : 25, AREA, getnpcid()); // closed ? opening : closing
+ .dir = .dir == 0 ? 2 : 6; // closed ? opening : closing
+ .busy = true; // lock until available again
+ initnpctimer;
+ }
+ end;
+
+OnTimer220:
+ .dir = .dir == 6 ? 0 : 4; // closing ? closed : open
+ end;
+
+OnTimer500:
+ .busy = false; // unlock
+
+ if (.dir == 0)
+ {
+ stopnpctimer; // stop here if the chest is closed
+ }
+ end;
+
+OnUnTouch:
+ if (getareausers(.x - 2, .y - 4, .x + 2, .y + 6) > 0 || .dir == 0)
+ {
+ end;
+ }
+OnTimer30000:
+ .busy = true;
+ .dir = 6; // closing
+ specialeffect(25, AREA, getnpcid()); // closing
+ setnpctimer 0;
+OnTouch:
+ end;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-22/hammock.txt b/npc/001-2-22/hammock.txt
new file mode 100644
index 00000000..f6f70044
--- /dev/null
+++ b/npc/001-2-22/hammock.txt
@@ -0,0 +1,137 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Animated hammock at the mid level of the ship.
+
+001-2-22,32,27,0 script #hammockArtis1 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,32,25,0 script #hammockArtis2 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,25,0 script #hammockArtis3 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,27,0 script #hammockArtis4 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,29,0 script #hammockArtis5 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,34,0 script #hammockArtis6 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,36,0 script #hammockArtis7 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,38,0 script #hammockArtis8 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,37,40,0 script #hammockArtis9 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,32,38,0 script #hammockArtis10 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-22,32,40,0 script #hammockArtis11 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchLeft;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
diff --git a/npc/001-2-22/knife.txt b/npc/001-2-22/knife.txt
new file mode 100644
index 00000000..25d03b88
--- /dev/null
+++ b/npc/001-2-22/knife.txt
@@ -0,0 +1,47 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Qwerty Dragon
+// Description:
+// Knife on the table.
+// Variable:
+// ShipQuests_Knife
+// Values:
+// 0 Default, not taken.
+// 1 Knife taken.
+
+000-2-1,50,24,0 script #Artisknife NPC_KNIVES,{
+ .@q = getq(ShipQuests_Knife);
+ if (.@q) close;
+
+ mesn "Narrator";
+ mesc(l("There are some knives on the table. Would you like to take one?"), 9);
+ next;
+
+ menu
+ l("Yes."), L_Give,
+ l("No."), -;
+
+ closeclientdialog;
+ close;
+
+L_Give:
+ mes "";
+ inventoryplace Knife, 1;
+
+ setq ShipQuests_Knife, 1;
+ getitem Knife, 1;
+
+ mesn "Narrator";
+ mesc(l("To open your inventory, use the F3 key or use your mouse to select it in the above menu in your client."), 9);
+ next;
+ mesc(l("When your inventory is open, you can equip an item by selecting it and clicking 'Equip'. You can do the same to unequip an item by clicking on 'Unequip'."), 9);
+ next;
+ mesc(l("Items have different effects. Some will heal you, some can be used as weapons or armor, and some can be sold for gold."), 9);
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-22/mapflags.txt b/npc/001-2-22/mapflags.txt
new file mode 100644
index 00000000..fdb4e3e2
--- /dev/null
+++ b/npc/001-2-22/mapflags.txt
@@ -0,0 +1 @@
+001-2-22 mapflag town
diff --git a/npc/001-2-22/note.txt b/npc/001-2-22/note.txt
new file mode 100644
index 00000000..8d39cd28
--- /dev/null
+++ b/npc/001-2-22/note.txt
@@ -0,0 +1,33 @@
+// Evol scripts.
+// Author:
+// Vasily_Makarov
+// Description:
+//
+
+001-2-22,31,31,0 script Note#001-2-22 NPC_DAN_NOTE,{
+ mesn;
+ mesq l("This note was left by somebody.");
+ next;
+ mesq l("What do you want to do with it?");
+
+ menu
+ l("Read it."), L_Content,
+ l("Leave it."), -;
+ close;
+
+L_Content:
+ mesn;
+ mes "\"" + l("Dear sister,");
+ mes l("In a couple of days, we will finally reach Artis.");
+ next;
+
+ mes l("I will send you this letter as soon as I arrive.");
+ mes l("Don't worry sister, I didn't forget you.");
+ next;
+
+ mes l("I would like to come back home when the days are better.");
+ mes l("And when we have enough money for ourselves without needing anybody else.");
+
+ mes l("Sincerely yours, Dan.") + "\"";
+ close;
+}
diff --git a/npc/001-2-22/peter.txt b/npc/001-2-22/peter.txt
new file mode 100644
index 00000000..dce6982d
--- /dev/null
+++ b/npc/001-2-22/peter.txt
@@ -0,0 +1,302 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Ablu
+// Alastrim
+// Jesusalva
+// Qwerty Dragon
+// Reid
+// Vasily_Makarov
+// Description:
+// Rat hunter.
+// 4+2 bits array:
+// ShipQuests
+// Variable:
+// ShipQuests_Peter
+// Values is a bitmask:
+// 0 Doesn't know the quest.
+// 1 Task given. (To prevent bugs because zero is a valid instance id)
+// 2 Already completed the first stage
+// 4 Already completed the second stage
+// 8 Already completed the third stage
+// ...
+// =15 Completed every stage.
+// Setq2:
+// Number of killed Rattos:
+// & 1 - Ratto 1
+// & 2 - Ratto 2
+// & 4 - Ratto 3
+// & 8 - Ratto 4
+// = 15: All rattos killed
+// (Adding more monsters etc. is possible, but be careful with the == 15 checks)
+// Setq3:
+// Instance ID (so we can destroy it later if needed, and check it too)
+// Others:
+// .@q = Peter variable.
+// PETER_TIME = gettimetick(2) for daily
+// @peter = Control Variable
+// @pt_mob = Control Variable
+// @MAP_NAME$ = Control Variable
+// "001-2-23" - map with mobs.
+
+001-2-22,72,34,0 script AreaNPC#Artis NPC_HIDDEN,0,1,{
+ end;
+OnTouch:
+ doevent "Peter::OnPeterMain";
+ close;
+}
+
+001-2-22,70,35,0 script Peter#Artis NPC_RATTO_SAILOR,{
+ goto L_Main;
+
+OnPeterMain:
+L_Main:
+ .@q = getq(ShipQuests_Peter);
+ .@q2 = getq2(ShipQuests_Peter);
+ .@q3 = getq3(ShipQuests_Peter);
+ if (BaseLevel < 5) goto OnTooWeak;
+
+ if (!.@q || !isinstance(.@q3) || .@q3 <= 0) goto L_Task;
+ if (.@q2 < 15) goto L_ReturnFail;
+ dispbottom l("I am broken?! Please report! Debug data: @@ (@@)", .@q, .@q2);
+ close;
+
+OnGiveTask:
+L_Task:
+ if (!.@q)
+ setq ShipQuests_Peter, 1, 0, -1;
+ mesn;
+ mesq l("Hey there!");
+ next;
+ mesq l("I need somebody who can rid the hold of the ship of these rattos. Can you help me?");
+ next;
+
+ menu
+ l("Yeah, but what reward will I get?"), L_BonusTask,
+ l("Why not, I need to train anyway."), L_BonusTask,
+ l("No, they are way too dangerous for me!"), -;
+
+ mes "";
+ mesn;
+ mesq l("Hehe, hehe. Well, come back if you change your mind.");
+
+ close;
+
+// Friendly reminder that you have about 20 secs to finish
+OnLowTime:
+ if ((getmap() ~= "001-2-22") || (getmap() ~= "nard*"))
+ dispbottom l("I'm starting to feel dizzy... I shouldn't stay here much longer.");
+ end;
+
+// Minimum Quest Level (any difficulty setting) is on L_Main (and currently is 5)
+OnTooWeak:
+ mesn;
+ mesq l("I need someone to help me clean the edge of the ship, but you aren't strong enough for now.");
+
+ close;
+
+/*
+OnStop:
+ slide 72, 36;
+
+ mesn;
+ mesq l("You can't go there!");
+
+ close;
+*/
+
+// This is cast if player dies in Basement, but not automatically (bad design?)
+// instance_destroy() is being recklessy called here, some sanity check is good.
+OnReturnFail:
+L_ReturnFail:
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3); // This would allow players to try again at once, but is DANGEROUS!
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
+ mesn;
+ mesq l("I see it's not so easy to get rid of these rattos. Do you want to try again?");
+ next;
+
+ menu
+ l("Yeah, but I would like to make sure I get a reward."), L_BonusTask,
+ l("Why not, I need to train anyway."), L_BonusTask,
+ l("No, they are way too dangerous for me!"), -;
+
+ mes "";
+ mesn;
+ mesq l("Hehe, hehe. Well, come back if you change your mind.");
+
+ close;
+
+
+L_BonusTask:
+ mes "";
+ mesn;
+ mesq l("There are three kind of monsters which frequently or seldomly attacks our fair vessel.");
+ next;
+ mesn;
+ .@q = getq(ShipQuests_Peter);
+ if (!(.@q & 2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Tortuga));
+ mes l("I'll give you @@ GP for this job.", 500);
+ mes "";
+ }
+ if (!(.@q & 4)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 1000);
+ mes "";
+ }
+ if (!(.@q & 8)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Croc));
+ mes l("I'll give you @@ GP for this job.", 1500);
+ mes "";
+ }
+ // If you already took all three bounties, you can only repeat the quest daily
+ if (.@q == 15 && PETER_TIME <= gettimetick(2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 750);
+ } else if (.@q == 15) {
+ mes l("I don't need your help right now, but maybe tomorrow, who knows?");
+ close;
+ }
+ next;
+
+ select
+ l("I'm not feeling like it today... Sorry."),
+ rif(!(.@q & 2), l("I will take the @@ Bounty.", "Tortuga")),
+ rif(!(.@q & 4), l("I will take the @@ Bounty.", "Ratto")),
+ rif(!(.@q & 8), l("I will take the @@ Bounty.", "Croc")),
+ rif(.@q == 15, l("Why not, I need to train anyway."));
+
+ if (@menu == 1)
+ close;
+
+ @peter=@menu;
+
+ goto L_Start;
+
+// In Moubootaur Legends, there's a small tutorial about Hit'n'run here
+// I didn't add it here but that can be arranged
+L_Start:
+// Init Instance
+OnStartOutside:
+ .@ID=getcharid(0);
+ @MAP_NAME$="nard@"+str(.@ID); // Max 4 chars for map name
+ .@INSTID = instance_create("ratto@a"+(.@ID), getcharid(3), IOT_CHAR);
+ .@instanceMapName$ = instance_attachmap("001-2-23", .@INSTID, 0, @MAP_NAME$);
+
+ // Instance already exists, or something went wrong
+ if (.@instanceMapName$ == "") {
+ mesn;
+ mesq l("Actually, you just took a bounty, right?");
+ next;
+ mesn;
+ mesq l("Why don't you take a break? Breath in some fresh air. The basement is pretty damp.");
+ close;
+ }
+
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, .@INSTID;
+
+ // It'll be self-destroyed when time runs out (3 minutes)
+ instance_set_timeout(180, 180, .@INSTID);
+ instance_init(.@INSTID);
+
+ // Save in a less reliable way the challenge you took
+ if (@peter == 2) {
+ @peter=2;
+ @pt_mob=Tortuga;
+ } else if (@peter == 3) {
+ @peter=4;
+ @pt_mob=Ratto;
+ } else if (@peter == 4) {
+ @peter=8;
+ @pt_mob=Croc;
+ } else {
+ @peter=0;
+ @pt_mob=Ratto;
+ }
+
+ warp @MAP_NAME$, 48, 28;
+ // Control how much time you have left
+ addtimer(120000, "Peter#Artis::OnLowTime");
+ addtimer(140000, "Peter#Artis::OnTimeout");
+
+ // Spawn the Monsters
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto1Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto2Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto3Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto4Death";
+
+ dispbottom l("Okay, you can start!");
+ closeclientdialog;
+ close;
+
+// TODO: This is very reckless, instance_destroy() could possibly affect others
+// If you agree with me, we can force player to wait until instance expire on its
+// own (3 minutes after start) instead of allowing immediate retry. That's safer,
+// and code will end up looking like Mundane (exploiting attach_map failures)
+
+// (Or if you are set in disregarding this, just uncomment instance_destroy.)
+// (Don't blame me if server SIGSEGV's because that, though)
+OnTimeout:
+ if (!(getmap() ~= "001-2-23") && !(getmap() ~= "nard*"))
+ end;
+ warp "001-2-22", 72, 36;
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
+ mesn;
+ mesq l("Hey! Be careful. You can't stay in this basement for so long, you're going to get sick. Come outside and take a break, maybe you can try again later.");
+ close;
+
+// This is called by npc/001-2-23/ratto.txt and completes the quest
+// Just like OnReturnFail and OnTimeout, this recklessy destroys the instance
+// It's not _buggy_, it is just reckless. I would like a setting to restrict it
+// to destroy only instances owned by the char, or to destroy by name :p
+OnDone:
+ warp "001-2-22", 72, 36;
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ if (@peter)
+ setq ShipQuests_Peter, getq(ShipQuests_Peter)|@peter, 0, -1;
+
+ .@q = getq(ShipQuests_Peter);
+ mesn;
+ mesq l("Good job!") + " " + l("Here's your reward!");
+
+
+ // Before handling the rewards, we should be sure we'll handle daily loop.
+ // You're already in daily phase if @peter is zero.
+ // PS. This is not exactly "daily", this is actually a forced 24-hours wait.
+ if (!@peter) {
+ PETER_TIME=gettimetick(2)+24*60*60;
+ @peter=1; // This allows you to get 32 EXP from daily repeat. Tweak as needed.
+ }
+
+ // You get some EXP based on difficulty taken
+ getexp @peter*32, @peter;
+
+ // We don't need @peter anymore, so reuse it to give you GP rewards
+ switch (@peter) {
+ case 2: @peter=500; break;
+ case 4: @peter=1000; break;
+ case 8: @peter=1500; break;
+ default: @peter=750; break;
+ }
+
+ Zeny += @peter;
+ message strcharinfo(0), l("You receive @@ E!", @peter);
+
+ // Some cleanup. Shouldn't cause bugs but it's absence causes a ugly behavior.
+ deltimer("Peter#Artis::OnLowTime");
+ deltimer("Peter#Artis::OnTimeout");
+ @peter=0;
+ close;
+
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/001-2-23/_import.txt b/npc/001-2-23/_import.txt
new file mode 100644
index 00000000..22778b22
--- /dev/null
+++ b/npc/001-2-23/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-23: Hold
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-23/_warps.txt",
+"npc/001-2-23/doors.txt",
+"npc/001-2-23/mapflags.txt",
+"npc/001-2-23/ratto.txt",
diff --git a/npc/001-2-23/_warps.txt b/npc/001-2-23/_warps.txt
new file mode 100644
index 00000000..d9434efb
--- /dev/null
+++ b/npc/001-2-23/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-23: Hold warps
+001-2-23,48,29,0 warp #001-2-23_48_29 0,0,001-2-22,72,35
diff --git a/npc/001-2-23/doors.txt b/npc/001-2-23/doors.txt
new file mode 100644
index 00000000..9c91e824
--- /dev/null
+++ b/npc/001-2-23/doors.txt
@@ -0,0 +1,75 @@
+// Evol scripts.
+// Authors:
+// Ablu
+// Alastrim
+// Jesusalva
+// Reid
+// Description:
+// Doors NPCs.
+
+001-2-23,48,29,0 script DoorUpwards#Artis NPC_HIDDEN,0,0,{
+
+OnTouch:
+ // Actually this will never work because Instanced map
+ if (mobcount("001-2-23","all") > 0) goto L_Warn;
+
+ goto L_Warp;
+
+L_Warn:
+ .@q = getq(ShipQuests_Peter);
+ if (.@q >= 15) goto L_Warp;
+
+ mesn "Narrator";
+ mesc(l("There are still some monsters left! Do you want to abort the quest?"), 9);
+ next;
+
+ menu
+ l("Yes."), L_Warp,
+ l("No."), -;
+
+ slide 48, 28;
+ closeclientdialog;
+ close;
+
+L_Warp:
+ warp "001-2-22", 72, 36;
+
+ deltimer("Peter#Artis::OnLowTime");
+ deltimer("Peter#Artis::OnTimeout");
+ closeclientdialog;
+ close;
+}
+
+// Besides the door, Alige is hiding himself and would rather not be disturbed
+001-2-23,24,31,0 script LeftDoor#Artis NPC_HIDDEN,0,0,{
+
+OnTouch:
+ mesn "Narrator";
+ mesc(l("It seems that you need a key to open this door."), 9);
+ next;
+ mesc(l("What do you want to do?"), 9);
+ next;
+
+ menu
+ rif(countitem(JohanneKey) > 0, l("Use the key.")), L_Warp,
+ l("Break the door."), L_Break,
+ l("Go away."), -;
+
+ closeclientdialog;
+ close;
+
+L_Break:
+
+ mes "";
+ mesn "Narrator";
+ mesc(l("You hear a loud scream. It must be the creaking of the wooden door..."), 9);
+
+ close;
+
+L_Warp:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Wait, it seems someone is blocking the door from the other side!"), 9);
+
+ close;
+}
diff --git a/npc/001-2-23/mapflags.txt b/npc/001-2-23/mapflags.txt
new file mode 100644
index 00000000..c8d2d7e7
--- /dev/null
+++ b/npc/001-2-23/mapflags.txt
@@ -0,0 +1 @@
+001-2-23 mapflag nosave 001-2-22,50,38
diff --git a/npc/001-2-23/ratto.txt b/npc/001-2-23/ratto.txt
new file mode 100644
index 00000000..24bb1e1a
--- /dev/null
+++ b/npc/001-2-23/ratto.txt
@@ -0,0 +1,98 @@
+// Evol Script.
+// Author:
+// Ablu
+// Alastrim
+// Jesusalva
+// Reid
+// Description:
+// Ratto killer.
+// The only "lose" conditions are:
+// 1- dying, but this is not handled anywhere
+// 2- Time running out, Peter handles that automatically.
+// Note that if you die here, you won't be able to return and will need to
+// start the quest over again. (I wonder why it is not handled by an OnDeath event)
+// iirc, logout will automatically destroy the instance and clear timers, so it
+// doesn't needs the script writer to handle logout cleanup (only death).
+
+001-2-23,0,0,0 script RattosControl#Artis NPC_HIDDEN,{
+ end;
+
+// Each monster on the basement have its own respawn cycle.
+// We use a XOR (^) operand to mark that the killed monster is not dead anymore.
+// This is to reproduce as accurate as possible the legacy behavior of the quest.
+OnRatto1Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^1;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto1Death";
+ end;
+
+OnRatto2Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^2;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto2Death";
+ end;
+
+OnRatto3Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^4;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto3Death";
+ end;
+
+OnRatto4Respawn:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^8;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto4Death";
+ end;
+
+// When you kill a monster on basement, we must check the mob as dead, see if you
+// finally killed the last one and quest is complete, and add a timer to respawn it
+// after 1m25s (for flavor purposes, makes quest harder though)
+OnRatto1Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|1;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto1Respawn");
+ end;
+
+OnRatto2Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|2;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto2Respawn");
+ end;
+
+OnRatto3Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|4;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto3Respawn");
+ end;
+
+OnRatto4Death:
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|8;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto4Respawn");
+ end;
+
+// This label is reached when all rattos are dead. We clear the respawn timers
+// (as we are going to delete the instance map anyway), warp you outside, and
+// from there onwards, Peter handles properly rewarding you.
+L_Victor:
+ deltimer("RattosControl#Artis::OnRatto1Respawn");
+ deltimer("RattosControl#Artis::OnRatto2Respawn");
+ deltimer("RattosControl#Artis::OnRatto3Respawn");
+ deltimer("RattosControl#Artis::OnRatto4Respawn");
+ addtimercount("Peter#Artis::OnTimeout", 5000);
+ addtimer(5000, "Peter#Artis::OnDone");
+ dispbottom l("It looks like all monsters were killed.");
+ end;
+}
diff --git a/npc/001-2-24/_import.txt b/npc/001-2-24/_import.txt
new file mode 100644
index 00000000..34c43a0b
--- /dev/null
+++ b/npc/001-2-24/_import.txt
@@ -0,0 +1,7 @@
+// Map 001-2-24: Nard's Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-24/_warps.txt",
+"npc/001-2-24/hammock.txt",
+"npc/001-2-24/mapflags.txt",
+"npc/001-2-24/nard.txt",
+"npc/001-2-24/piourocket.txt",
diff --git a/npc/001-2-24/_warps.txt b/npc/001-2-24/_warps.txt
new file mode 100644
index 00000000..945c3aca
--- /dev/null
+++ b/npc/001-2-24/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-24: Nard's Room warps
+001-2-24,19,27,0 warp #001-2-24_19_27 0,0,001-2-21,32,28
diff --git a/npc/001-2-24/hammock.txt b/npc/001-2-24/hammock.txt
new file mode 100644
index 00000000..f4319358
--- /dev/null
+++ b/npc/001-2-24/hammock.txt
@@ -0,0 +1,17 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Animated hammock at the top level of the ship.
+
+001-2-24,28,24,0 script #nardArtisHammock NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch:
+ hamTouchRight;
+
+OnUnTouch:
+ hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
diff --git a/npc/001-2-24/mapflags.txt b/npc/001-2-24/mapflags.txt
new file mode 100644
index 00000000..4506b385
--- /dev/null
+++ b/npc/001-2-24/mapflags.txt
@@ -0,0 +1 @@
+001-2-24 mapflag town
diff --git a/npc/001-2-24/nard.txt b/npc/001-2-24/nard.txt
new file mode 100644
index 00000000..c38081e4
--- /dev/null
+++ b/npc/001-2-24/nard.txt
@@ -0,0 +1,93 @@
+// Evol scripts.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Captain Nard dialogs.
+// Nard does the introduction with a small quest.
+// This quest is meant to teach the player how to use a weapon,and to bring food to the ship.
+// 4 bits array:
+// ShipQuests
+// Variable:
+// 0 ShipQuests_Nard
+// 1 ShipQuests_Gugli
+// 2 ShipQuests_ChefGado
+// Values:
+// 00 Introduction of the boxes and Nard. This is displayed when the player never spoke to Nard or his box.
+// 01 Nard spoke and gave access to the outdoor of the ship.
+// 02 Completed the Gugli quest.
+// 03 ChefGado Quest accepted.
+// 04 ChefGado Quest completed and "Introduction" chapter finalized.
+// 05 Reward taken from the box.
+// 10 Never talked with Gugli.
+// 11 Gugli gives you the task.
+// 12 Gave all of the boxes to Gugli.
+
+001-2-24,25,26,0 script Nard#Artis NPC_NARD,{
+
+ checkclientversion;
+ mesn;
+ mesq l("Good day sir or madam.");
+ next;
+ mesq l("What can I do for you?");
+ .@q = getq(ArtisQuests_Enora);
+
+ // Before the player sees Enora, the menu shows L_Lost on top
+ // If the player saw Enora, the menu shows L_Lost at the bottom
+ // Because he shouldn't be lost after having talked to her, so the priority in menu changes
+ menu
+ rif(.@q == 0, l("I'm lost, where should I go?")), L_Lost,
+ rif(.@q > 0, l("Tell me, where are we right now?")), L_Info,
+ l("How long will you stay here?"), -,
+ rif(.@q > 0, l("I'm lost, where should I go?")), L_Lost;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("We just returned from a long journey and Artis is a good city to rest and to conclude our exchange."),
+ l("I think that we will stay in port for a great time."),
+ l("Although, if you want to visit a place nearby, we could take you there."),
+ l("Do you want to go somewhere?");
+
+ switch (select(l("Drasil Island."),
+ l("Nowhere, I'm fine here.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Let's set sail then!");
+
+ savepoint "000-2-1", 50, 38;
+ if (!getmapxy(.@map$, .@x, .@y, 0))
+ {
+ warp "000-2-3", .@x, .@y;
+ }
+ else
+ {
+ warp "000-2-3", 22, 27;
+ }
+
+ closeclientdialog;
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ok we stay docked here if you need our help.");
+
+ closeclientdialog;
+ close;
+ }
+L_Info:
+ closeclientdialog;
+ npctalk3 l("Don't you recognize the great city of Artis?");
+ close;
+
+L_Lost:
+ mes "";
+ mesn;
+ mesq l("Julia made an appeal to the Legion of Aemil to get in touch with you, exit the ship and you should see your escort!");
+ next;
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 5;
+ end;
+}
diff --git a/npc/001-2-24/piourocket.txt b/npc/001-2-24/piourocket.txt
new file mode 100644
index 00000000..3bcc914b
--- /dev/null
+++ b/npc/001-2-24/piourocket.txt
@@ -0,0 +1,9 @@
+// Evol scripts.
+// Author:
+// Ablu
+// Description:
+// Jumping piou.
+
+// actual source is in npc/000-2-3/piourocket.txt
+
+001-2-24,27,23,4 duplicate(#piourocket) #piourocketArtis NPC_PIOU_ROCKET
diff --git a/npc/001-2-25/_import.txt b/npc/001-2-25/_import.txt
new file mode 100644
index 00000000..a3e9ee03
--- /dev/null
+++ b/npc/001-2-25/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-25: Storage Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-25/_mobs.txt",
+"npc/001-2-25/_warps.txt",
+"npc/001-2-25/mapflags.txt",
diff --git a/npc/001-2-25/_mobs.txt b/npc/001-2-25/_mobs.txt
new file mode 100644
index 00000000..de0c289e
--- /dev/null
+++ b/npc/001-2-25/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-25: Storage Room mobs
+001-2-25,0,0,0,0 monster Ratto 1005,2,240000,420000
diff --git a/npc/001-2-25/_warps.txt b/npc/001-2-25/_warps.txt
new file mode 100644
index 00000000..88fd273d
--- /dev/null
+++ b/npc/001-2-25/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-25: Storage Room warps
+001-2-25,29,31,0 warp #001-2-25_29_31 0,0,001-2-19,41,26
diff --git a/npc/001-2-25/mapflags.txt b/npc/001-2-25/mapflags.txt
new file mode 100644
index 00000000..659308e5
--- /dev/null
+++ b/npc/001-2-25/mapflags.txt
@@ -0,0 +1 @@
+001-2-25 mapflag town
diff --git a/npc/001-2-26/_import.txt b/npc/001-2-26/_import.txt
new file mode 100644
index 00000000..ab0c2970
--- /dev/null
+++ b/npc/001-2-26/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-26: Alchemy Lab
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-26/_warps.txt",
+"npc/001-2-26/flask.txt",
+"npc/001-2-26/ivan.txt",
+"npc/001-2-26/mapflags.txt",
diff --git a/npc/001-2-26/_warps.txt b/npc/001-2-26/_warps.txt
new file mode 100644
index 00000000..2b16f569
--- /dev/null
+++ b/npc/001-2-26/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-26: Alchemy Lab warps
+001-2-26,28,43,0 warp #001-2-26_28_43 0,0,001-1,163,71
diff --git a/npc/001-2-26/flask.txt b/npc/001-2-26/flask.txt
new file mode 100644
index 00000000..8afa58c3
--- /dev/null
+++ b/npc/001-2-26/flask.txt
@@ -0,0 +1,21 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Alchemy animation.
+
+001-2-26,32,27,4 script #FlaskAlchemyLab NPC_FLASK,{
+ .dir = 2;
+ stopnpctimer;
+ initnpctimer;
+ close;
+
+OnTimer12920:
+ .dir = 4;
+ stopnpctimer;
+ end;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/001-2-26/ivan.txt b/npc/001-2-26/ivan.txt
new file mode 100644
index 00000000..ba95fd4c
--- /dev/null
+++ b/npc/001-2-26/ivan.txt
@@ -0,0 +1,85 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Alchemist NPC
+
+001-2-26,28,30,0 script Ivan NPC_IVAN,{
+
+ function ivan_description {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I am an alchemist, I bear the name of Ivan."),
+ l("I work under the protection and the supervision of the Legion of Aemil."),
+ l("Alchemical studies are prohibited in every city of the Archipelagos, do not dare to practice it in a public zone!");
+
+ return;
+ }
+
+ function enora_quest {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("How many? What kind? I can produce two dozen boxes per day.");
+
+ select(l("5 Piberries Infusions"));
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("5 boxes... Alright, @@ are my speciality!", getitemlink(PiberriesInfusion)),
+ l("I can prepare them in an hour or so!");
+
+ select(l("You missunderstood, it's 5 potions."));
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Why would the Legion request my help for only 5 potions?"),
+ l("Is this some kind of joke?!");
+
+ switch (select(l("Enora needs them."),
+ l("Excuse me that was a mistake.")))
+ {
+ case 1:
+ break;
+ case 2:
+ narrator S_FIRST_BLANK_LINE, l("Ivan grumbles and resumes his work.");
+ emotion E_UPSET;
+ close;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh... You should have started with this!"),
+ l("I have some spare one, take them, and tell Enora that any fees are paid!");
+
+ setq ArtisQuests_Enora, 9;
+ emotion E_HAPPY;
+ return;
+ }
+
+ .@enora = getq(ArtisQuests_Enora);
+
+ if (.@enora < 8)
+ {
+ npctalk3 l("I'm busy, leave me alone.");
+ end;
+ }
+
+ speech S_LAST_NEXT, l("Yes what do you need?");
+
+ select
+ rif(.@enora == 8, l("The Legion needs some potions.")),
+ rif(.@enora >= 8, l("Who are you?")),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ enora_quest;
+ break;
+ case 2:
+ ivan_description;
+ break;
+ }
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-26/mapflags.txt b/npc/001-2-26/mapflags.txt
new file mode 100644
index 00000000..20c3188d
--- /dev/null
+++ b/npc/001-2-26/mapflags.txt
@@ -0,0 +1 @@
+001-2-26 mapflag town
diff --git a/npc/001-2-27/_import.txt b/npc/001-2-27/_import.txt
new file mode 100644
index 00000000..977f4132
--- /dev/null
+++ b/npc/001-2-27/_import.txt
@@ -0,0 +1,8 @@
+// Map 001-2-27: Blacksmith Shop
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-27/_warps.txt",
+"npc/001-2-27/don.txt",
+"npc/001-2-27/kaylo.txt",
+"npc/001-2-27/lydon.txt",
+"npc/001-2-27/mapflags.txt",
+"npc/001-2-27/shop.txt",
diff --git a/npc/001-2-27/_warps.txt b/npc/001-2-27/_warps.txt
new file mode 100644
index 00000000..e69b24d1
--- /dev/null
+++ b/npc/001-2-27/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-27: Blacksmith Shop warps
+001-2-27,35,35,0 warp #001-2-27_35_35 0,0,001-1,101,108
diff --git a/npc/001-2-27/don.txt b/npc/001-2-27/don.txt
new file mode 100644
index 00000000..9db092b1
--- /dev/null
+++ b/npc/001-2-27/don.txt
@@ -0,0 +1,112 @@
+// Evol scripts.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// Don the blacksmith of Artis
+
+001-2-27,35,29,0 script Don#001-2-27 NPC_HUMAN_MALE_OLD,{
+ function improve_equipment;
+ function card_explanation;
+ function take_apprentice;
+ function good_blacksmith;
+
+ speech S_LAST_NEXT,
+ l("Hi, what do you want kiddo?");
+
+ do
+ {
+ switch (.@q = select(l("How can I improve my equipment?"),
+ l("What is a card?"),
+ l("Are you a good blacksmith?"),
+ l("Do you take apprentices?"),
+ l("Nothing.")))
+ {
+ case 1:
+ improve_equipment();
+ break;
+ case 2:
+ card_explanation();
+ break;
+ case 3:
+ good_blacksmith();
+ break;
+ case 4:
+ take_apprentice();
+ break;
+ case 5:
+ break;
+ }
+ } while (.@q != 5);
+
+ goodbye;
+ close;
+
+function improve_equipment {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Different ways, each part of your equipment can be generally upgraded."),
+ l("You rarely use the full potential of your equipment. As they say, a master weapon in a noob's hands is a noob weapon with wasted potential. But the more you use them, the better you can harness this power."),
+ l("Power obtained from proficiency will be noted down near the equipment name. There may be illegal ways to raise proficiency without hard work. But things obtained without hard work are not worth it."),
+ l("You can also improve your equipment in a totally different way with the use of cards."),
+ l("By last, a master craftsman can make equipment much better than a less skilled one. Equipment made by measure are much better than those bought at shops as well.");
+ return;
+}
+
+function card_explanation {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("There are two different kinds of cards, the first changes the style of your clothes, the second changes their stats."),
+ l("I am not an expert of the first kind, but I know what I am talking about when it comes to improving equipment."),
+ l("A stat card works on different pieces of equipment."),
+ l("Each piece of equipment has a predefined slot number."),
+ l("Each card improves your gear by a ratio or a fixed number on a predefined stat."),
+ l("Like, a defensive mythril card can be used on any mythril equipment, and it will improve the defense by 5% of the latter."),
+ l("You just have to select the card, then you choose which piece of equipment you want to use it on, and you are done."),
+ l("I am also aware that you can slot runestones and even gemstones to equipment as well. Some of them have magic properties.");
+ return;
+}
+
+function take_apprentice {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I do not.");
+
+ emotion E_UPSET;
+
+ select(l("What about Chelios?"));
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Chelios was stubborn in his youth, he never stopped annoying me with his questions while I was working at the forge."),
+ l("He did not change while growing up, I repeatedly asked him to leave the forge but in the end he installed himself in front of it..."),
+ l("He is mature and he rarely ask questions so I am fine. I can not stand the sight of a whiner anyway.");
+ return;
+}
+
+function good_blacksmith {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I do not like to brag about it but you won't find a better blacksmith on the whole island."),
+ l("If you need somebody to craft a weapon or a plate from diagrams I am the one that you need.");
+
+ switch (select(l("Can I craft them myself?"),
+ l("Ok.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You can try if you know the recipe, but your chance of success is lesser than a well trained smith and master craftsman.");
+ .@s = SmithSystem(CRAFT_SMITHERY);
+ if (.@s)
+ mesc l("Success!"), 3;
+ else
+ mesc l("That didn't work!"), 1;
+ next;
+ break;
+ case 2:
+ break;
+ }
+
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/001-2-27/kaylo.txt b/npc/001-2-27/kaylo.txt
new file mode 100644
index 00000000..805f8dea
--- /dev/null
+++ b/npc/001-2-27/kaylo.txt
@@ -0,0 +1,43 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Kaylo is the Shield seller in Don's Blacksmith house on Artis.
+
+001-2-27,27,28,0 script Kaylo NPC_KAYLO,{
+ speech S_LAST_NEXT,
+ l("Hi customer! What do you want today?");
+
+ switch (select(
+ l("Let's make a trade."),
+ l("What's wrong with your clothes?"),
+ l("What is this place?"),
+ l("See you.")))
+ {
+ case 1:
+ closeclientdialog;
+ shop "Store#Shield001-2-27";
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I used a card to improve my clothes."),
+ l("There are two different kinds of cards, the first changes the style of your clothes, the second changes their stats."),
+ l("You should discuss with Don and Calypsan if you want to learn more about it, they are masters on this area!");
+ break;
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You are in the Blacksmith's house, by Jove!"),
+ l("Don is a renowned blacksmith throughout Andorra, it's crazy that you never heard of him.");
+ break;
+ case 4:
+ break;
+ }
+
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/001-2-27/lydon.txt b/npc/001-2-27/lydon.txt
new file mode 100644
index 00000000..3fc93178
--- /dev/null
+++ b/npc/001-2-27/lydon.txt
@@ -0,0 +1,36 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Lydon is the Weapon seller in Don's Blacksmith house on Artis.
+
+001-2-27,43,28,0 script Lydon NPC_LYDON,{
+ speech S_LAST_NEXT,
+ l("Hi customer! What do you want today?");
+
+ switch (select(
+ l("Let's make a trade."),
+ l("Who is the blacksmith outside?"),
+ l("Bye.")))
+ {
+ case 1:
+ closeclientdialog;
+ shop "Store#Weapon001-2-27";
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Chef? He is Don's apprentice, he works on his hammering skill day and night."),
+ l("He is very lucky that Don took him under his wing, but being the student of such a teacher is not easy every day!");
+ break;
+ case 3:
+ break;
+ }
+
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/001-2-27/mapflags.txt b/npc/001-2-27/mapflags.txt
new file mode 100644
index 00000000..42bba366
--- /dev/null
+++ b/npc/001-2-27/mapflags.txt
@@ -0,0 +1 @@
+001-2-27 mapflag town
diff --git a/npc/001-2-27/shop.txt b/npc/001-2-27/shop.txt
new file mode 100644
index 00000000..3cbee6f4
--- /dev/null
+++ b/npc/001-2-27/shop.txt
@@ -0,0 +1,62 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Blacksmith shops
+
+001-2-27,27,29,0 trader Store#Shield001-2-27 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem LeatherShield, -1, 30;
+ sellitem CopperArmbands, -1, 28;
+ sellitem IronArmbands, -1, 20;
+
+ .distance = 2;
+ end;
+
+OnClock0000:
+ restoreshopitem LeatherShield, 10;
+ restoreshopitem CopperArmbands, 9;
+ restoreshopitem IronArmbands, 7;
+OnClock0800:
+ restoreshopitem LeatherShield, 10;
+ restoreshopitem CopperArmbands, 6;
+ restoreshopitem IronArmbands, 3;
+OnClock01600:
+ restoreshopitem LeatherShield, 10;
+ restoreshopitem CopperArmbands, 8;
+ restoreshopitem IronArmbands, 6;
+ end;
+}
+
+001-2-27,43,29,0 trader Store#Weapon001-2-27 NPC_NO_SPRITE,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem PiouSlayer, -1, 50;
+ sellitem TrainingGladius, -1, 25;
+ sellitem WoodenSword, -1, 50;
+ sellitem TrainingArrow, -1, 20000;
+
+ .distance = 2;
+ end;
+
+OnClock0000:
+ restoreshopitem PiouSlayer, 25;
+ restoreshopitem TrainingGladius, 8;
+ restoreshopitem WoodenSword, 25;
+OnClock0800:
+ restoreshopitem PiouSlayer, 25;
+ restoreshopitem TrainingGladius, 8;
+ restoreshopitem WoodenSword, 25;
+OnClock01600:
+ restoreshopitem PiouSlayer, 25;
+ restoreshopitem TrainingGladius, 8;
+ restoreshopitem WoodenSword, 25;
+ restoreshopitem TrainingArrow, 20000;
+ end;
+}
diff --git a/npc/001-2-28/_import.txt b/npc/001-2-28/_import.txt
new file mode 100644
index 00000000..a58d3fee
--- /dev/null
+++ b/npc/001-2-28/_import.txt
@@ -0,0 +1,8 @@
+// Map 001-2-28: Red Plush Inn
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-28/_warps.txt",
+"npc/001-2-28/jenna.txt",
+"npc/001-2-28/mapflags.txt",
+"npc/001-2-28/note.txt",
+"npc/001-2-28/plush.txt",
+"npc/001-2-28/shop.txt",
diff --git a/npc/001-2-28/_warps.txt b/npc/001-2-28/_warps.txt
new file mode 100644
index 00000000..4447ee63
--- /dev/null
+++ b/npc/001-2-28/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-28: Red Plush Inn warps
+001-2-28,29,42,0 warp #001-2-28_29_42 0,0,001-1,118,89
+001-2-28,61,30,0 warp #001-2-28_61_30 0,0,001-1,135,83
+001-2-28,34,25,0 warp #001-2-28_34_25 3,0,001-2-29,38,34
diff --git a/npc/001-2-28/jenna.txt b/npc/001-2-28/jenna.txt
new file mode 100644
index 00000000..5043e064
--- /dev/null
+++ b/npc/001-2-28/jenna.txt
@@ -0,0 +1,78 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Description:
+// Jenna, waitress in Artis inn.
+
+001-2-28,52,32,0 script Jenna#001-2-28 NPC_RAIJIN_FEMALE_WAITRESS,1,1,{
+
+ function SayRandomGreeting {
+
+ .@tick = gettimetick(1);
+ if (.@tick > @Artis_RedPlush_WaitressTick + 10)
+ {
+ setarray .messages$[0], l("Welcome to our inn!"),
+ l("Welcome to Red Plush."),
+ l("Please, have a seat."),
+ l("Lovely day, isn't it?");
+
+ .@r = rand(getarraysize(.messages$));
+ .@msg$ = .messages$[.@r];
+ npctalk3 .@msg$;
+ @Artis_RedPlush_WaitressTick = .@tick;
+ }
+ }
+
+ speech S_LAST_NEXT, l("Do you want a drink?");
+
+ closeclientdialog;
+ shop "#Invisible001-2-28";
+ close;
+
+OnTimer1000:
+ dographmovestep;
+
+OnTouch:
+ SayRandomGreeting;
+ end;
+
+OnHour00:
+ if (playerattached())
+ @Artis_RedPlush_WaitressTick = 0;
+ end;
+
+OnInit:
+ .distance = 5;
+ initmovegraph "m_table_1", 52, 32,
+ "m_table_2", 56, 32,
+ "big_table_l", 53, 27,
+ "big_table_r", 56, 30,
+ "s_table_1", 53, 36,
+ "s_table_2", 58, 38,
+ "lf_table_2", 45, 31;
+
+ setmovegraphcmd "m_table_1", "s_table_2", 2, "dir 4; wait 8",
+ "m_table_1", "lf_table_2", 1, "dir 4; wait 8",
+ "m_table_1", "big_table_l",1, "dir 0; wait 10",
+ "m_table_2", "m_table_1", 1, "dir 0; wait 8",
+ "m_table_2", "lf_table_2", 1, "dir 4; emote 2; wait 8",
+ "m_table_2", "big_table_l",2, "dir 0; wait 8",
+ "s_table_1", "m_table_1", 5, "dir 0; wait 10",
+ "s_table_1", "big_table_l",3, "dir 0; wait 1; emote 103;"
+ "say Thank you for the tip!;"
+ "wait 15; moveon",
+ "s_table_1", "m_table_2", 1, "dir 0; wait 8",
+ "s_table_2", "s_table_1", 1, "wait 6",
+ "s_table_2", "m_table_2", 1, "dir 0; wait 8",
+ "big_table_l", "m_table_2", 1, "dir 0; wait 6",
+ "big_table_l", "s_table_1", 1, "dir 2; wait 6",
+ "big_table_r", "s_table_1", 1, "dir 2; wait 6",
+ "big_table_r", "m_table_2", 2, "wait 8",
+ "big_table_r", "s_table_2", 1, "dir 4; wait 8",
+ "lf_table_2", "m_table_2", 1, "dir 0; wait 8",
+ "lf_table_2", "big_table_r",1, "dir 4; wait 1; emote 3; wait 6";
+
+ firstmove "wait 8";
+ initnpctimer;
+}
+
diff --git a/npc/001-2-28/mapflags.txt b/npc/001-2-28/mapflags.txt
new file mode 100644
index 00000000..8cf7ec21
--- /dev/null
+++ b/npc/001-2-28/mapflags.txt
@@ -0,0 +1 @@
+001-2-28 mapflag town
diff --git a/npc/001-2-28/note.txt b/npc/001-2-28/note.txt
new file mode 100644
index 00000000..2c41adb7
--- /dev/null
+++ b/npc/001-2-28/note.txt
@@ -0,0 +1,43 @@
+// Evol scripts.
+// Authors:
+// gumi
+// Qwerty Dragon
+// Reid
+// WildX
+// Jesusalva
+// Description:
+// A small note presenting the main rules of Evol Online.
+
+001-2-28,36,28,0 script Note#001-2-28 NPC_PAPER_NOTE,{
+ narrator S_LAST_NEXT,
+ l("There is a paper with some rules written on it.");
+
+ GameRules 8 | 4;
+
+ narrator S_NO_NPC_NAME,
+ l("Following these lines are some other writings on this paper."),
+ l("Do not give the password of your room to anybody! Keep it secret and try not to use the same one in any other room in the future. - Jenna"),
+ l("You'll gain experience if you hang around here with friends. Ask Jenna for drinks and pay a round for them! - Management");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
+// This is part of AFKing Experience
+001-2-28,60,30,0 script #AFKArtis NPC_HIDDEN,0,1,{
+ end;
+
+OnTouch:
+ addtimer2(3000, "#AFKArtis::OnSpeeching");
+ end;
+
+OnSpeeching:
+ AFKLoop("#AFKArtis::OnSpeeching", "001-2-28", 36, 27, 60, 42);
+ end;
+}
+
+001-2-28,36,31,0 duplicate(#AFKArtis) #AFKArtis2 NPC_HIDDEN,0,1
+
diff --git a/npc/001-2-28/plush.txt b/npc/001-2-28/plush.txt
new file mode 100644
index 00000000..695bd7c6
--- /dev/null
+++ b/npc/001-2-28/plush.txt
@@ -0,0 +1,127 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Red, the Innkeeper.
+// Variable:
+// INN_REGISTER
+
+001-2-28,28,28,0 script Plush#001-2-28 NPC_RED,{
+
+ function narrator_explication {
+ narrator S_LAST_NEXT,
+ l("You will respawn at this place if defeated in combat."),
+ l("All you have to do is to select a bed in the upper level anytime after your reservation."),
+ l("Unlike other respawn points, an inn can fully restore your HP."),
+ l("Of course, you can select a bed somewhere else after your reservation, but you won't get your HP recovery until you choose to get some rest in the inn."),
+ l("You can also use your room to get some rest after a long battle. That will consume your reservation but your HP will be fully restored.");
+ return;
+ }
+
+ function accepted_room {
+ .@price = getarg(0);
+ if (Zeny < .@price)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("You don't have enough money, bring @@ E.", .@price);
+ }
+ else
+ {
+ emotion E_HAPPY;
+ Zeny -= .@price;
+ INN_REGISTER = REDPLUSH_INN;
+ PC_IS_DEAD = false;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I registered you on one of the rooms of the upper level."),
+ l("You can go upstairs and choose a different room if you want.");
+ savepoint "001-2-29", 29, any(49, 35);
+ }
+ }
+
+ function register_room {
+ .@price = lognbaselvl(100, 10);
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That will be @@ E to set your respawn point", .@price),
+ l("This will remain your respawn point until set elsewhere."),
+ l("Is that okay?");
+
+ if (askyesno() == ASK_YES)
+ {
+ accepted_room(.@price);
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Come back later if you changed your mind!");
+ }
+
+ return;
+ }
+
+ function lodge_check {
+ if (INN_REGISTER == NO_INN)
+ {
+ register_room;
+ }
+ else if (INN_REGISTER == REDPLUSH_INN)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You are already registered here."),
+ l("Go on the upper level if you want to change your room or to use it.");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("If you are registered somewhere else you will loose that reservation."),
+ l("Do you still want to lodge here?");
+
+ if (askyesno() == ASK_YES)
+ {
+ register_room;
+ }
+ }
+ return;
+ }
+
+ speech S_LAST_NEXT,
+ l("Welcome to the Red Plush inn!"),
+ l("What do you need?");
+
+ do
+ {
+ .@q = select(
+ l("Could I lodge here for a while?"),
+ l("What service do you offer?"),
+ l("What is your tipiou trying to do?"),
+ l("Nothing."));
+
+ switch (.@q)
+ {
+ case 1:
+ lodge_check;
+ break;
+ case 2:
+ emotion E_WINK;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("We offer a room for travelers passing by Artis, our beds are comfy and you can be guaranteed to be right as rain after a night here!"),
+ l("If you wake up at the inn after a harsh battle, you will find yourself revitalized in an instant unlike other places where you can rest.");
+
+ narrator_explication;
+ break;
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That poor one is doing his best to fly... But his last meal and the gravity is not helping him so far!");
+ break;
+ case 4:
+ break;
+ }
+ } while (.@q != 1 && .@q != 4);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 5;
+}
diff --git a/npc/001-2-28/shop.txt b/npc/001-2-28/shop.txt
new file mode 100644
index 00000000..5e05a7dd
--- /dev/null
+++ b/npc/001-2-28/shop.txt
@@ -0,0 +1,24 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Inn hidden shop.
+
+001-2-28,53,33,0 trader #Invisible001-2-28 NPC_HIDDEN,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem RedPlushWine, -1, 50;
+
+ .distance = 10;
+ end;
+
+OnClock0000:
+ restoreshopitem RedPlushWine, 20;
+OnClock0800:
+ restoreshopitem RedPlushWine, 20;
+OnClock1600:
+ restoreshopitem RedPlushWine, 20;
+}
diff --git a/npc/001-2-29/_import.txt b/npc/001-2-29/_import.txt
new file mode 100644
index 00000000..ebcab6d1
--- /dev/null
+++ b/npc/001-2-29/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-29: First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-29/_savepoints.txt",
+"npc/001-2-29/_warps.txt",
+"npc/001-2-29/mapflags.txt",
diff --git a/npc/001-2-29/_savepoints.txt b/npc/001-2-29/_savepoints.txt
new file mode 100644
index 00000000..c2176e4c
--- /dev/null
+++ b/npc/001-2-29/_savepoints.txt
@@ -0,0 +1,54 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-29: First Floor saves
+001-2-29,29,28,0 script #save_001-2-29_29_28 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, REDPLUSH_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-29,29,35,0 script #save_001-2-29_29_35 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, REDPLUSH_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-29,29,42,0 script #save_001-2-29_29_42 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, REDPLUSH_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-29,29,49,0 script #save_001-2-29_29_49 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, REDPLUSH_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-29/_warps.txt b/npc/001-2-29/_warps.txt
new file mode 100644
index 00000000..6c9d08f9
--- /dev/null
+++ b/npc/001-2-29/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-29: First Floor warps
+001-2-29,39,35,0 warp #001-2-29_39_35 3,0,001-2-28,33,27
+001-2-29,38,25,0 warp #001-2-29_38_25 0,1,001-2-30,36,31
diff --git a/npc/001-2-29/mapflags.txt b/npc/001-2-29/mapflags.txt
new file mode 100644
index 00000000..98a4373f
--- /dev/null
+++ b/npc/001-2-29/mapflags.txt
@@ -0,0 +1 @@
+001-2-29 mapflag town
diff --git a/npc/001-2-3/_import.txt b/npc/001-2-3/_import.txt
new file mode 100644
index 00000000..c003e206
--- /dev/null
+++ b/npc/001-2-3/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-3: First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-3/_savepoints.txt",
+"npc/001-2-3/_warps.txt",
+"npc/001-2-3/mapflags.txt",
diff --git a/npc/001-2-3/_savepoints.txt b/npc/001-2-3/_savepoints.txt
new file mode 100644
index 00000000..e835aaa1
--- /dev/null
+++ b/npc/001-2-3/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-3: First Floor saves
+001-2-3,42,32,0 script #save_001-2-3_42_32 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-3/_warps.txt b/npc/001-2-3/_warps.txt
new file mode 100644
index 00000000..ddd0b6e1
--- /dev/null
+++ b/npc/001-2-3/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-3: First Floor warps
+001-2-3,27,31,0 warp #001-2-3_27_31 2,0,001-2-2,27,31
diff --git a/npc/001-2-3/mapflags.txt b/npc/001-2-3/mapflags.txt
new file mode 100644
index 00000000..311c2c75
--- /dev/null
+++ b/npc/001-2-3/mapflags.txt
@@ -0,0 +1 @@
+001-2-3 mapflag town
diff --git a/npc/001-2-30/_import.txt b/npc/001-2-30/_import.txt
new file mode 100644
index 00000000..91918ef5
--- /dev/null
+++ b/npc/001-2-30/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-30: Second Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-30/_mobs.txt",
+"npc/001-2-30/_warps.txt",
+"npc/001-2-30/mapflags.txt",
diff --git a/npc/001-2-30/_mobs.txt b/npc/001-2-30/_mobs.txt
new file mode 100644
index 00000000..956ecf5d
--- /dev/null
+++ b/npc/001-2-30/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-30: Second Floor mobs
+001-2-30,0,0,0,0 monster Ratto 1005,1,240000,420000
diff --git a/npc/001-2-30/_warps.txt b/npc/001-2-30/_warps.txt
new file mode 100644
index 00000000..60c227f8
--- /dev/null
+++ b/npc/001-2-30/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-30: Second Floor warps
+001-2-30,37,32,0 warp #001-2-30_37_32 1,0,001-2-29,37,27
diff --git a/npc/001-2-30/mapflags.txt b/npc/001-2-30/mapflags.txt
new file mode 100644
index 00000000..357de0aa
--- /dev/null
+++ b/npc/001-2-30/mapflags.txt
@@ -0,0 +1 @@
+001-2-30 mapflag town
diff --git a/npc/001-2-31/_import.txt b/npc/001-2-31/_import.txt
new file mode 100644
index 00000000..ef587396
--- /dev/null
+++ b/npc/001-2-31/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-31: West Commercial Building
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-31/_warps.txt",
+"npc/001-2-31/mapflags.txt",
diff --git a/npc/001-2-31/_warps.txt b/npc/001-2-31/_warps.txt
new file mode 100644
index 00000000..2dfa6c99
--- /dev/null
+++ b/npc/001-2-31/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-31: West Commercial Building warps
+001-2-31,32,40,0 warp #001-2-31_32_40 0,0,001-1,49,97
+001-2-31,36,32,0 warp #001-2-31_36_32 0,0,001-2-41,25,32
diff --git a/npc/001-2-31/mapflags.txt b/npc/001-2-31/mapflags.txt
new file mode 100644
index 00000000..a7f18782
--- /dev/null
+++ b/npc/001-2-31/mapflags.txt
@@ -0,0 +1 @@
+001-2-31 mapflag town
diff --git a/npc/001-2-32/_import.txt b/npc/001-2-32/_import.txt
new file mode 100644
index 00000000..b59046e0
--- /dev/null
+++ b/npc/001-2-32/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-32: Training Arena Lobby
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-32/_warps.txt",
+"npc/001-2-32/doors.txt",
+"npc/001-2-32/mapflags.txt",
+"npc/001-2-32/serena.txt",
diff --git a/npc/001-2-32/_warps.txt b/npc/001-2-32/_warps.txt
new file mode 100644
index 00000000..4db4b354
--- /dev/null
+++ b/npc/001-2-32/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-32: Training Arena Lobby warps
+001-2-32,27,33,0 warp #001-2-32_27_33 0,0,001-2-33,39,33
diff --git a/npc/001-2-32/doors.txt b/npc/001-2-32/doors.txt
new file mode 100644
index 00000000..828366d2
--- /dev/null
+++ b/npc/001-2-32/doors.txt
@@ -0,0 +1,38 @@
+// Evol scripts.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// Doors NPCs.
+
+001-2-32,33,29,0 script ToFightRoom#001-2-32 NPC_HIDDEN,0,0,{
+
+OnTouch:
+ if (getq(Artis_Legion_Progress) < 3)
+ {
+ narrator
+ l("You hear some sound behind the door."),
+ l("Somebody is probably training, better wait for them to finish.");
+ }
+ else
+ {
+ .@q2=getq2(Artis_Legion_Progress);
+ .@mapn$="atl2@"+getcharid(0);
+ // FIXME This code is extremely unreliable
+ if (isinstance(.@q2) && .@q2 >= 0)
+ {
+ instance_set_timeout(3600, 3600, .@q2);
+ warp .@mapn$, 24, 29;
+ } else {
+ .@inst = instance_create("ATL "+getcharid(0), getcharid(3), IOT_CHAR);
+ instance_attachmap("001-2-35", .@inst, false, .@mapn$);
+ // Instance lasts one hour
+ instance_set_timeout(3600, 3600, .@inst);
+ instance_init(.@inst);
+ setq2 Artis_Legion_Progress, .@inst;
+ }
+
+ }
+
+ close;
+}
diff --git a/npc/001-2-32/mapflags.txt b/npc/001-2-32/mapflags.txt
new file mode 100644
index 00000000..8225ecbe
--- /dev/null
+++ b/npc/001-2-32/mapflags.txt
@@ -0,0 +1 @@
+001-2-32 mapflag town
diff --git a/npc/001-2-32/serena.txt b/npc/001-2-32/serena.txt
new file mode 100644
index 00000000..d7d18a41
--- /dev/null
+++ b/npc/001-2-32/serena.txt
@@ -0,0 +1,215 @@
+// The Mana World scripts.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// Artis's Legion of Aemil officier of the fighting room.
+// Note:
+// ATL - Artis Training Legion
+
+001-2-32,27,27,0 script Serena NPC_SERENA,{
+ mesn;
+ mesq l("Oh darling, what brought you here?"); // TRANSLATORS: Darling - Expresses familiarity or elderliness in relation to PC.
+ next;
+ select
+ l("I wanna fight."),
+ l("Nothing.");
+ mes "";
+ if (@menu == 1) {
+ mes l("Just walk right and talk to me. I'll be there in no time.");
+ mesc l("Challenge time limit: 60 minutes after entering the room.");
+ }
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
+001-2-35,26,27,0 script Serena#Ctrl NPC_SERENA,{
+ function checkVictory;
+
+ // We can't begin if we're already doing it
+ if (.atlf) {
+ // TODO: We should check if the timers are running
+ //doevent(instance_npcname(.name$)+"::OnVerify");
+ if (getq(Artis_Legion_Progress) == 4)
+ npctalk l("You're already done with the training, so feel free to leave.");
+ else
+ npctalk l("Focus on the fight!");
+ end;
+ }
+
+ // Enemies of the Legion of Aemil cannot train, obviously
+ if (faction_standing("LEGION", true) < 1) {
+ mesn;
+ mesq l("Sorry, but I can only train you if Lieutenant Lozerk authorizes.");
+ close;
+ }
+
+ // Otherwise, begin it
+ mesn;
+ mesq l("Are you ready for your training?");
+ next;
+ if (askyesno() == ASK_NO) {
+ mesn;
+ mesq l("Oh dear, please come back later then.");
+ close;
+ }
+ @ATLFIGHT=true;
+ // FALL THROUGH
+
+OnBegin:
+ mapannounce getmap(), l("Training Arena, %s, get ready!", strcharinfo(0)), bc_all;
+ // Save permanent data
+ .atl_blv=BaseLevel;
+ .atl_Str=readbattleparam(getcharid(3), UDT_STR);
+ .atl_Agi=readbattleparam(getcharid(3), UDT_AGI);
+ .atl_Vit=readbattleparam(getcharid(3), UDT_VIT);
+ .atl_Int=readbattleparam(getcharid(3), UDT_INT);
+ .atl_Dex=readbattleparam(getcharid(3), UDT_DEX);
+ .atl_Luk=readbattleparam(getcharid(3), UDT_LUK);
+ .atl_Dly=readbattleparam(getcharid(3), UDT_ADELAY);
+ .atl_Rng=readbattleparam(getcharid(3), UDT_ATKRANGE);
+
+ // Save (b)ase data
+ .atl_bhp=MaxHp;
+ .atl_bAtk1=readbattleparam(getcharid(3), UDT_ATKMIN);
+ .atl_bAtk2=readbattleparam(getcharid(3), UDT_ATKMAX);
+ .atl_bMatk=readbattleparam(getcharid(3), UDT_MATKMAX);
+ .atl_bDef=readbattleparam(getcharid(3), UDT_DEF);
+ .atl_bMdef=readbattleparam(getcharid(3), UDT_MDEF);
+ .atl_bHit=readbattleparam(getcharid(3), UDT_FLEE)*8/10;
+ .atl_bFlee=readbattleparam(getcharid(3), UDT_HIT)*7/10;
+ .atl_bCrit=readbattleparam(getcharid(3), UDT_CRIT);
+
+ // Save (p)rogression data
+ .atl_php=.atl_bhp/6;
+ .atl_pAtk1=.atl_bAtk1/12;
+ .atl_pAtk2=.atl_bAtk2/12;
+ .atl_pMatk=.atl_bMatk/5;
+ .atl_pDef=.atl_bDef/5;
+ .atl_pMdef=.atl_bMdef/5;
+ .atl_pHit=.atl_bFlee/10;
+ .atl_pFlee=.atl_bHit/15;
+ .atl_pCrit=.atl_bCrit/10;
+
+ // Begin the battle
+ doevent(instance_npcname(.name$)+"::OnGladius");
+ addtimer(5000, instance_npcname(.name$)+"::OnVerify");
+ closeclientdialog;
+ close;
+
+OnGladius:
+ sleep(800);
+ // TODO: Coordinates, Helpers?
+ .@mg=monster(instance_mapname("001-2-35"), any(25, 30, 35), any(29, 35, 40, 46), "Gladiator", any(LegionSwordswoman, LegionHalberdier, LegionLieutenant, LegionLieutenant), 1, instance_npcname(.name$)+"::OnGladius");
+
+ // Set "permanent" data
+ setunitdata(.@mg, UDT_ADELAY, .atl_Dly-.atlf);
+ setunitdata(.@mg, UDT_ATKRANGE, .atl_Rng+cap_value(.atlf/10, 0, 3));
+
+ // Set base data
+ setunitdata(.@mg, UDT_LEVEL, .atl_blv+.atlf);
+ setunitdata(.@mg, UDT_STR, .atl_Str+.atlf);
+ setunitdata(.@mg, UDT_AGI, .atl_Agi+.atlf);
+ setunitdata(.@mg, UDT_VIT, .atl_Vit+.atlf);
+ setunitdata(.@mg, UDT_INT, .atl_Int+.atlf);
+ setunitdata(.@mg, UDT_DEX, .atl_Dex+.atlf);
+ setunitdata(.@mg, UDT_LUK, .atl_Luk+.atlf);
+
+ // Set variable data
+ setunitdata(.@mg, UDT_MAXHP, .atl_bhp+.atl_php*(.atlf-1));
+ setunitdata(.@mg, UDT_HP, .atl_bhp+.atl_php*(.atlf-1));
+
+ setunitdata(.@mg, UDT_ATKMIN, .atl_bAtk1+.atl_pAtk1*(.atlf-1));
+ setunitdata(.@mg, UDT_ATKMAX, .atl_bAtk2+.atl_pAtk2*(.atlf-1));
+ setunitdata(.@mg, UDT_MATKMIN, .atl_bMatk+.atl_pMatk*(.atlf-1));
+ setunitdata(.@mg, UDT_MATKMAX, .atl_bMatk+.atl_pMatk*(.atlf-1));
+ setunitdata(.@mg, UDT_DEF, .atl_bDef+.atl_pDef*(.atlf-1));
+ setunitdata(.@mg, UDT_MDEF, .atl_Mdef+.atl_pMdef*(.atlf-1));
+ setunitdata(.@mg, UDT_HIT, .atl_bHit+.atl_pHit*(.atlf-1));
+ setunitdata(.@mg, UDT_FLEE, .atl_bFlee+.atl_pFlee*(.atlf-1));
+ setunitdata(.@mg, UDT_CRIT, .atl_bCrit+.atl_pCrit*(.atlf-1));
+
+ setunitdata(.@mg, UDT_PDODGE, min(30, .atl_Luk/10+(.atlf/3)));
+
+ .atlf+=1;
+ mapannounce instance_mapname("001-2-35"), ("Training Arena, wave " + .atlf + "!"), bc_all;
+ maptimer(instance_mapname("001-2-35"), 10, instance_npcname(.name$)+"::OnATLUpdate");
+ end;
+
+OnATLUpdate:
+ if (.atlf > ATLRANK)
+ ATLRANK=.atlf;
+ getexp .atlf*7, .atlf*5; // Provide some reward
+ end;
+
+// Check for possible cheats, and update default values
+OnVerify:
+ if (!.atlf)
+ end;
+
+ if (readbattleparam(getcharid(3), UDT_ATKRANGE) > .atl_Rng)
+ .atl_Rng=readbattleparam(getcharid(3), UDT_ATKRANGE);
+
+ if (readbattleparam(getcharid(3), UDT_ATKMAX) > .atl_bAtk1) {
+ .atl_bAtk1=readbattleparam(getcharid(3), UDT_ATKMIN);
+ .atl_bAtk2=readbattleparam(getcharid(3), UDT_ATKMAX);
+ .atl_pAtk1=.atl_bAtk1/10;
+ .atl_pAtk2=.atl_bAtk2/10;
+ }
+
+ if (readbattleparam(getcharid(3), UDT_DEF) > .atl_bDef) {
+ .atl_bDef=readbattleparam(getcharid(3), UDT_DEF);
+ .atl_pDef=.atl_bDef/5;
+ }
+
+ if (readbattleparam(getcharid(3), UDT_MDEF) > .atl_bMdef) {
+ .atl_bMdef=readbattleparam(getcharid(3), UDT_MDEF);
+ .atl_pMdef=.atl_bMdef/5;
+ }
+
+ if (readbattleparam(getcharid(3), UDT_MATKMAX) > .atl_bMatk) {
+ .atl_bMatk=readbattleparam(getcharid(3), UDT_MATKMAX);
+ .atl_pMatk=.atl_bMatk/5;
+ }
+
+ // TODO: Ignore haste potion effects
+ // TODO: Update battle statuses on the fly
+ if (readbattleparam(getcharid(3), UDT_ADELAY) < .atl_bDly)
+ .atl_bDly=readbattleparam(getcharid(3), UDT_DELAY);
+
+ // Victory conditions
+ if (getq(Artis_Legion_Progress) == 3)
+ checkVictory();
+
+ addtimer(5000, instance_npcname(.name$)+"::OnVerify");
+ end;
+
+ // Victory conditions
+ function checkVictory {
+ if (.atlf > 3) {
+ npctalk l("Congratulations, %s. I think this is enough. You can continue fighting to set a good score or report to Lozerk.", strcharinfo(0));
+ // Duplicate the dialog in case player miss it
+ dispbottom l("Congratulations, %s. I think this is enough. You can continue fighting to set a good score or report to Lozerk.", strcharinfo(0));
+ setq Artis_Legion_Progress, 4, 0;
+ }
+ return;
+ }
+
+}
+
+// Helper function for failure
+function script ATLFightEnd {
+ if (@ATLFIGHT) {
+ @ATLFIGHT=false;
+ .@mapn$="atl2@"+getcharid(0);
+ killmonster(.@mapn$, "all", false);
+ .@q2=getq2(Artis_Legion_Progress);
+ set(getvariableofnpc(.atlf, instance_npcname("Serena#Ctrl", .@q2)), 0);
+ }
+ return;
+}
+
+
diff --git a/npc/001-2-33/_import.txt b/npc/001-2-33/_import.txt
new file mode 100644
index 00000000..7dadf6f8
--- /dev/null
+++ b/npc/001-2-33/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-33: Legion of Aemil Headquarters
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-33/_warps.txt",
+"npc/001-2-33/lozerk.txt",
+"npc/001-2-33/mapflags.txt",
+"npc/001-2-33/triggers.txt",
diff --git a/npc/001-2-33/_warps.txt b/npc/001-2-33/_warps.txt
new file mode 100644
index 00000000..73adf059
--- /dev/null
+++ b/npc/001-2-33/_warps.txt
@@ -0,0 +1,53 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-33: Legion of Aemil Headquarters warps
+001-2-33,29,32,0 script #001-2-33_29_32_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-34", 29, 32;
+close;
+
+OnUnTouch:
+ doevent "#001-2-33_29_32::OnUnTouch";
+}
+001-2-33,29,32,0 script #001-2-33_29_32 NPC_ARTIS_IN_DOOR,1,2,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-2-33,39,32,0 script #001-2-33_39_32_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-32", 27, 32;
+close;
+
+OnUnTouch:
+ doevent "#001-2-33_39_32::OnUnTouch";
+}
+001-2-33,39,32,0 script #001-2-33_39_32 NPC_ARTIS_IN_DOOR,1,2,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
+001-2-33,45,30,0 warp #001-2-33_45_30 0,0,001-2-38,24,28
+001-2-33,23,30,0 warp #001-2-33_23_30 0,0,001-2-37,36,28
+001-2-33,25,40,0 warp #001-2-33_25_40 2,0,001-2-40,27,46
+001-2-33,43,40,0 warp #001-2-33_43_40 2,0,001-2-40,45,46
+001-2-33,34,46,0 warp #001-2-33_34_46 0,0,001-1,57,42
diff --git a/npc/001-2-33/lozerk.txt b/npc/001-2-33/lozerk.txt
new file mode 100644
index 00000000..12a1614f
--- /dev/null
+++ b/npc/001-2-33/lozerk.txt
@@ -0,0 +1,195 @@
+// Evol scripts.
+// Authors:
+// monwarez
+// Reid
+// Tirifto
+// Description:
+// Sword trainer from the Legion of Aemil guild.
+// Variables:
+// Artis_Legion_Progress
+// Values:
+// 0 Default.
+// 1 Sent to training.
+// 2 Finished training.
+// 3 Sent to battle.
+// 4 Finished battle.
+// 5 Sent to Q'Anon.
+
+001-2-33,34,33,0 script Lozerk NPC_DEMON_MALE_SWORD,{
+
+ // Quest-related functions
+
+ function explain_direction {
+
+ switch (getq(Artis_Legion_Progress))
+ {
+ case 1:
+ setcamnpc "#001-2-33_29_32";
+
+ speech(S_LAST_NEXT | S_NO_NPC_NAME,
+ l("It's to the west, on your left side. Just go through this door before the stairs and turn left afterwards. Can't miss it!"),
+ l("Talk to Hector and he'll show you the ropes."),
+ l("Report back to me once you've had enough!"));
+
+ restorecam;
+
+ break;
+ case 3:
+ setcamnpc "#001-2-33_39_32";
+
+ speech(S_LAST_NEXT | S_NO_NPC_NAME,
+ l("The room is to the east, on your right side. Just go through the door before the stairs and then turn right. It's like the mirror image of our training room."));
+
+ restorecam;
+ break;
+ case 5:
+ setcamnpc "#001-2-33_45_28";
+
+ speech(S_LAST_NEXT | S_NO_NPC_NAME,
+ l("Walk up the stairs, go through the door on either side, and the only other door in the room, few steps to the south, will lead you right to him."));
+
+ restorecam;
+ break;
+ }
+
+ return;
+ }
+
+ function send_training {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh, you were sent by Enora!"),
+ l("If Enora thinks this is the right place for you, then she's probably be right. Did you know she's a lieutenant of the Legion?"),
+ l("The rank of lieutenant is granted only to people with proper control of their skill and good judgment, like Enora. Or me, of course."),
+ l("By the way, I'm Lozerk. Lieutenant Lozerk.");
+
+ select(l("Pleasure to meet you. I am @@.", strcharinfo(PC_NAME)));
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh, you are that person! You were stranded in the seas for a while, right? You look like it."),
+ l("But don't you worry! I don't know how to get you back your memories, but we can work on your muscles for now!"),
+ l("After all, this is the Legion of Aemil! You want to be a great warrior? We'll make you one here!"),
+ l("For starters, you should probably do some stretching and practice on some dummies in our training room."),
+ l("That's right, we have our very own training room. The Legion is always well prepared!");
+
+ setq Artis_Legion_Progress, 1;
+ explain_direction();
+
+ return;
+ }
+
+ function send_battle {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("So, did you get your blood boiling? Give the dummies a good lesson? Good!"),
+ l("But since it's not dummies that will go after you out there, this training won't be enough."),
+ l("If you want to make a formidable foe for anyone, you'll need to train with real living opponents!"),
+ l("Of course, the Legion of Aemil can easily provide you with such training, even if you're not a member. Just great, isn't it?"),
+ l("We have a special room for this purpose, too. You may test your skills against all kinds of dreadful monsters in there.");
+
+ setq Artis_Legion_Progress, 3;
+ explain_direction();
+
+ return;
+ }
+
+ function send_qanon {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("And you won! That means you should be able to handle yourself in battle from now on."),
+ l("If you keep it up, you'll eventually become a fearsome warrior, just like me!"),
+ l("Or almost like me, at the very least."),
+ l("But if you really want to accomplish something, you should consider joining us."),
+ l("You have talent and the best place to utilize it is in the Legion! You can either pursue your goals with us or without us, but trust me, with us it's much better."),
+ l("I should know, I've not been a member for a while, too. But then I joined the Legion and look what a shining example of a great fighter I became!"),
+ l("You should definitely go talk to Q'Anon, our boss. You'll find him upstairs.");
+
+ setq Artis_Legion_Progress, 5;
+ explain_direction();
+
+ return;
+ }
+
+ // Normal functions
+
+ function forget_direction {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You are lucky there are no mental faculty requirements to join the Legion!");
+
+ explain_direction;
+
+ return;
+ }
+
+ function tell_about_legion {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("The Legion of Aemil is the greatest organization on all continent! A town cannot be safer than when it's under our protection."),
+ l("This is where the bravest of warriors come together to put their skills to a good use, for a good cause."),
+ l("Our building here is also the finest place in the town. Just go and see for yourself!");
+
+ return;
+ }
+
+ function praise_sword {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thanks!");
+
+ return;
+ }
+
+ // Conversation
+
+ speech S_LAST_NEXT,
+ l("Welcome to the Legion of Aemil's building in Artis!");
+
+ // You're an enemy of the Legion - No dialog for you
+ if (faction_standing("LEGION", true) < 1) {
+ mesn;
+ mesq l("Please don't loiter around unless you have business with the Legion.");
+ close;
+ }
+
+
+ do
+ {
+ .@legion_progress = getq(Artis_Legion_Progress);
+ .@enora = getq(ArtisQuests_Enora);
+ consolemes(CONSOLEMES_DEBUG, .@legion_progress + " " + .@enora);
+ select
+ rif((.@legion_progress == 0) && (.@enora == 11), l("Enora sent me here.")),
+ rif(.@legion_progress == 2, l("I'm done with my training.")),
+ rif(.@legion_progress == 4, l("I'm back from battle!")),
+ rif(.@legion_progress == 1 || .@legion_progress == 3 || .@legion_progress == 5, l("Where should I go?")),
+ l("What can you tell me about the legion?"),
+ l("That's a nice sword you have there."),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ send_training;
+ break;
+ case 2:
+ send_battle;
+ break;
+ case 3:
+ send_qanon;
+ break;
+ case 4:
+ forget_direction;
+ break;
+ case 5:
+ tell_about_legion;
+ break;
+ case 6:
+ praise_sword;
+ break;
+ }
+ } while(@menu != 7);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-2-33/mapflags.txt b/npc/001-2-33/mapflags.txt
new file mode 100644
index 00000000..4882b03e
--- /dev/null
+++ b/npc/001-2-33/mapflags.txt
@@ -0,0 +1,3 @@
+001-2-33 mapflag mask 13
+001-2-33 mapflag nosave 001-2-33,34,42
+001-2-33 mapflag town
diff --git a/npc/001-2-33/triggers.txt b/npc/001-2-33/triggers.txt
new file mode 100644
index 00000000..e540869c
--- /dev/null
+++ b/npc/001-2-33/triggers.txt
@@ -0,0 +1,102 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Artis Aemil's Legion triggers to add and remove masks.
+
+// Transition Top triggers
+001-2-33,26,35,0 script #001-2-33LeftRemTop NPC_HIDDEN,0,2,{
+OnTouch:
+ artisALResetMask;
+ close;
+}
+
+001-2-33,27,35,0 script #001-2-33LeftAddTop NPC_HIDDEN,0,2,{
+OnTouch:
+ artisALTopMask;
+ close;
+}
+
+001-2-33,42,35,0 script #001-2-33RightRemTop NPC_HIDDEN,0,2,{
+OnTouch:
+ artisALResetMask;
+ close;
+}
+
+001-2-33,41,35,0 script #001-2-33RightAddTop NPC_HIDDEN,0,2,{
+OnTouch:
+ artisALTopMask;
+ close;
+}
+
+// Transition Bottom triggers
+
+001-2-33,25,32,0 script #001-2-33LeftRemBot NPC_HIDDEN,1,0,{
+OnTouch:
+ artisALResetMask;
+ close;
+}
+
+001-2-33,25,31,0 script #001-2-33LeftAddBot NPC_HIDDEN,1,0,{
+OnTouch:
+ artisALBottomMask;
+ close;
+}
+
+001-2-33,43,32,0 script #001-2-33RightRemBot NPC_HIDDEN,1,0,{
+OnTouch:
+ artisALResetMask;
+ close;
+}
+
+001-2-33,43,31,0 script #001-2-33RightAddBot NPC_HIDDEN,1,0,{
+OnTouch:
+ artisALBottomMask;
+ close;
+}
+
+// Warped location triggers
+
+001-2-33,24,30,0 script #001-2-33WarpTopLeft NPC_HIDDEN,0,0,{
+OnTouch:
+ artisALBottomMask;
+ close;
+}
+
+001-2-33,44,30,0 script #001-2-33WarpTopRight NPC_HIDDEN,0,0,{
+OnTouch:
+ artisALBottomMask;
+ close;
+}
+
+// WarpMid is crazy and not working correctly, cause unknown.
+001-2-33,29,34,0 script #001-2-33WarpMidLeft NPC_HIDDEN,1,1,{
+OnTouch:
+ artisALTopMask;
+ close;
+}
+
+001-2-33,39,34,0 script #001-2-33WarpMidRight NPC_HIDDEN,1,1,{
+OnTouch:
+ artisALTopMask;
+ close;
+}
+
+001-2-33,34,45,0 script #001-2-33WarpArtis NPC_HIDDEN,2,3,{
+OnTouch:
+ artisALTopMask;
+ close;
+}
+
+// Bottom Warp location triggers
+001-2-33,43,39,0 script #001-2-33WarpBotLeft NPC_HIDDEN,1,0,{
+OnTouch:
+ artisALResetMask;
+ close;
+}
+
+001-2-33,25,39,0 script #001-2-33WarpBotRight NPC_HIDDEN,1,0,{
+OnTouch:
+ artisALResetMask;
+ close;
+}
diff --git a/npc/001-2-34/_import.txt b/npc/001-2-34/_import.txt
new file mode 100644
index 00000000..9ec74d40
--- /dev/null
+++ b/npc/001-2-34/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-34: Training Room Lobby
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-34/_warps.txt",
+"npc/001-2-34/doors.txt",
+"npc/001-2-34/mapflags.txt",
+"npc/001-2-34/samantha.txt",
diff --git a/npc/001-2-34/_warps.txt b/npc/001-2-34/_warps.txt
new file mode 100644
index 00000000..06f74a95
--- /dev/null
+++ b/npc/001-2-34/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-34: Training Room Lobby warps
+001-2-34,29,33,0 warp #001-2-34_29_33 0,0,001-2-33,29,33
diff --git a/npc/001-2-34/doors.txt b/npc/001-2-34/doors.txt
new file mode 100644
index 00000000..6161dfa4
--- /dev/null
+++ b/npc/001-2-34/doors.txt
@@ -0,0 +1,29 @@
+// Evol scripts.
+// Author:
+// Reid
+// Omatt
+// Toams
+// Jesus
+// Description:
+// Doors NPCs.
+
+001-2-34,23,29,0 script ToTrainingRoom#001-2-34 NPC_HIDDEN,0,0,{
+OnTouch:
+
+ .@q2=getq2(ArtisQuests_TrainingLegion);
+ // Map name limit: 4 chars (atl1)
+ .@mapn$="atl1@"+getcharid(0);
+ if (isinstance(.@q2) && .@q2 > 0) {
+ warp .@mapn$, 36, 30;
+ } else {
+ .@inst = instance_create("Training Room "+getcharid(0), getcharid(3), IOT_CHAR);
+ instance_attachmap("001-2-36", .@inst, false, .@mapn$);
+ // 30 minutes (1800s) inside, or 5 minutes (300s) outside
+ instance_set_timeout(1800, 300, .@inst);
+ instance_init(.@inst);
+ setq2 ArtisQuests_TrainingLegion, .@inst;
+ warp .@mapn$, 36, 30;
+ }
+
+ end;
+}
diff --git a/npc/001-2-34/mapflags.txt b/npc/001-2-34/mapflags.txt
new file mode 100644
index 00000000..b632f6fe
--- /dev/null
+++ b/npc/001-2-34/mapflags.txt
@@ -0,0 +1 @@
+001-2-34 mapflag town
diff --git a/npc/001-2-34/samantha.txt b/npc/001-2-34/samantha.txt
new file mode 100644
index 00000000..b69e87ed
--- /dev/null
+++ b/npc/001-2-34/samantha.txt
@@ -0,0 +1,54 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Artis's Legion of Aemil officier of the training room.
+// Twin sister of Serena.
+
+001-2-34,29,27,0 script Samantha NPC_SAMANTHA,{
+ mesn;
+ mesq l("Look who we have here, did you come for a training session?");
+ close;
+
+ // <scratch>
+ // [ PC]: I was just looking around.
+ // [NPC]: Did not someone offer guidance?
+ // [NPC]: Enora was supposed to be helping you...
+ // [NPC]: ...but, she is young, and often absent-minded; did you ask?
+ // [NPC]: (Alt.) It seems you rushed ahead of her. Go back and talk to Enora.
+ // ([Enora]: Beyond here is the fighting room o_o;)
+ // ([Enora]: I... uh... well, you will need alies in there.)
+ // ([Enora]: And... you see... this is my good outfit and...)
+ // ([Enora]: ...I've only just cleaned up in there >.>)
+ // But if you keep getting stronger; that will be the day.
+
+ // Alt-Ready:
+ // [NPC]: Beyond here is the Fight Room.
+ // [NPC]: [conditions]*
+ // [NPC]: Good-luck | Bonne-chance.
+
+ // (Alt.) [NPC]: I used to be an adventurer, like you.
+ // [NPC]: But there was no one to join for quests.
+ // [NPC]: So I enlisted for a post at this chapter.
+ // [NPC]: But my "friends" joined the Brotherhood!
+
+ // [NPC]: The Brotherhood knows a lot more about monsters.
+ // [NPC]: But they could not "break the Legion's power" without burning all cities to the ground.
+ // [NPC]: The cities grow fast, ruining farmers and peasants.
+ // [NPC]: Our differences lead to friction.
+
+ // Alt-What
+ // The secret is out: We really did create a mutant.
+ // None of the members were informed until it went out-of-control.
+ // [...]
+ // Muahaha-ha! My beautiful mutant. The city of Artis is mine.
+ // </scratch>
+
+ // Alt-Siege
+ // The city is being attacked. Go help the warriors and town-guard.
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-2-35/_import.txt b/npc/001-2-35/_import.txt
new file mode 100644
index 00000000..fa2c779b
--- /dev/null
+++ b/npc/001-2-35/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-35: Training Arena
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-35/doors.txt",
+"npc/001-2-35/mapflags.txt",
diff --git a/npc/001-2-35/doors.txt b/npc/001-2-35/doors.txt
new file mode 100644
index 00000000..64fcb30f
--- /dev/null
+++ b/npc/001-2-35/doors.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Jesusalva
+// Description:
+// Doors NPCs.
+
+001-2-35,23,29,0 script #001-2-35_23_29 NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ if (getq(Artis_Legion_Progress) < 4) {
+ dispbottom l("I am not a coward. I shall not give up!");
+ end;
+ }
+ ATLFightEnd();
+ warp "001-2-32", 32, 29;
+ end;
+}
+
diff --git a/npc/001-2-35/mapflags.txt b/npc/001-2-35/mapflags.txt
new file mode 100644
index 00000000..47166d55
--- /dev/null
+++ b/npc/001-2-35/mapflags.txt
@@ -0,0 +1,2 @@
+001-2-35 mapflag town
+001-2-35 mapflag nowarpto
diff --git a/npc/001-2-36/_import.txt b/npc/001-2-36/_import.txt
new file mode 100644
index 00000000..403b0b12
--- /dev/null
+++ b/npc/001-2-36/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-36: Training Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-36/_warps.txt",
+"npc/001-2-36/hector.txt",
+"npc/001-2-36/mapflags.txt",
diff --git a/npc/001-2-36/_warps.txt b/npc/001-2-36/_warps.txt
new file mode 100644
index 00000000..bcb74de9
--- /dev/null
+++ b/npc/001-2-36/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-36: Training Room warps
+001-2-36,37,30,0 warp #001-2-36_37_30 0,0,001-2-34,24,29
diff --git a/npc/001-2-36/hector.txt b/npc/001-2-36/hector.txt
new file mode 100644
index 00000000..b4f801be
--- /dev/null
+++ b/npc/001-2-36/hector.txt
@@ -0,0 +1,460 @@
+// TrainingRoom
+// Author:
+// jak1
+// omatt
+// toams
+// Story:
+// Reid
+// Teru
+// Spellchecking & Dialogs:
+// Reid
+// toams
+// Variable:
+// .fightingActive
+// 0 = no fight active
+// 1 = swordfight active
+// 2 = bowfight active
+// 3 = skillfight
+// ArtisQuests_TrainingLegion
+// 0 not started at all
+// 1 swordTraining finished
+// 2 bowTraining finished
+// 3 bow and sword finished
+// 4 end of training
+// .mobID is related to quest state
+//
+// TODO adding rand messages like "try hit it harder..." for wave's
+// TODO in first, second, and third training, input some tips about related weapon given.
+
+
+001-2-36,32,36,0 script Hector#001-2-36 NPC_LUCAS,{
+
+
+ 'instanceID = instance_id();
+ 'npcName$ = strnpcinfo(NPC_NAME_UNIQUE); // required for call the label in the npc of this one instance
+ attachnpctimer;
+ initnpctimer;
+
+ function waveEnded {
+
+ if (.fightingActive == 1)
+ {
+ npctalk3(l("Well done, you aren't even bleeding that much!"));
+ if (getq(.quest_training) == 0)
+ setq(.quest_training, 1);
+ if (getq(.quest_training) == 2)
+ setq(.quest_training, 3);
+ }
+ if (.fightingActive == 2)
+ {
+ npctalk3(l("Great! Don't mind those scorched hairs, they will grow back."));
+ if (getq(.quest_training) == 0)
+ setq(.quest_training, 2);
+ if (getq(.quest_training) == 1)
+ setq(.quest_training, 3);
+ }
+ if (.fightingActive == 3)
+ {
+ if (getq(.quest_training) == 3)
+ {
+ npctalk3(l("Congratulations, you have finished your training."));
+ sleep2(2000);
+ npctalk3(l("The only way to improve yourself is practice, practice and some more practice."));
+ setq(.quest_training, 4);
+ setq(Artis_Legion_Progress, 2);
+ }
+ else
+ {
+ npctalk3(l("You finished training the bashing skill. Pretty powerful isn't it?"));
+ }
+ }
+
+ .currentWaveLevel = 1;
+ .fightingActive = 0;
+ 'mobDead = 0;
+ end;
+ }
+
+ function mobSpawn {
+
+ if (.fightingActive != 0)
+ {
+ if (.currentWaveLevel == .maxWaves)
+ {
+ npctalk3(l("Last Wave!"));
+ }
+ else
+ {
+ npctalk3(l("Wave " + .currentWaveLevel + "!"));
+ }
+
+ areamonster('map$, .mobCoordinate[0], .mobCoordinate[1], .mobCoordinate[2], .mobCoordinate[3],
+ /* map x1 y1 x2 y2 */
+ strmobinfo(1, .mobID[.fightingActive]), .mobID[.fightingActive], .currentWaveLevel, 'npcName$+"::OnTrainingMobDead");
+ /* mob display mob id amount label */
+ }
+
+ end;
+ }
+
+ function trainingEnd {
+
+ sleep2(1500);
+ npctalk3(l("This training is over!"));
+ .fightingActive = 0;
+ .currentWaveLevel = 1;
+ killmonster('map$, "All");
+ stopnpctimer();
+ end;
+ }
+
+ function checkWeapon {
+ // check for sword in swordtraining
+ if (getiteminfo(getequipid(EQI_HAND_R), ITEMINFO_SUBTYPE) != W_1HSWORD && .fightingActive == 1)
+ {
+ npctalk3(l("Hey! Use your sword!"));
+ trainingEnd;
+ }
+
+ // check for bow in bowtraining
+ if (getiteminfo(getequipid(EQI_HAND_R), ITEMINFO_SUBTYPE) != W_BOW && .fightingActive == 2)
+ {
+ npctalk3(l("Hey! Use your bow!"));
+ trainingEnd;
+ }
+
+ // no weapons may be equiped when training skill
+ if (getequipid(EQI_HAND_R) != -1 && .fightingActive == 3)
+ {
+ npctalk3(l("Hey! No weapons allowed this round!"));
+ trainingEnd;
+ }
+
+ }
+
+
+ function mobKilled {
+
+ 'mobDead = 0; // reset the count
+
+ checkWeapon; // check if correct weapon is in use
+
+ // on first skill training give SM_BASH skill and explain how to use it.
+ if (getq(.quest_training) == 3 && .currentWaveLevel == 1)
+ {
+ setcamnpc(strnpcinfo(NPC_NAME_UNIQUE)); // focus the npc when he talk to the player
+ speech(S_LAST_NEXT,
+ l("Using a skill consumes Mana."),
+ l("It takes a while to have full Mana again."),
+ l("The more intelligence points you have, the faster it goes."),
+ l("If you sit, you regain your Mana faster."),
+ l("Or you can drink a mana potion. This restores some Mana. How much depends on the potion."),
+ l("Here take one! I have plenty of them."));
+ closedialog;
+ getitem(.mana_potion, 1);
+ sleep2(3000);
+ }
+
+ if (.currentWaveLevel == .maxWaves )
+ {
+ waveEnded;
+ }
+
+
+ .currentWaveLevel++; // next wave after killed dummy
+
+ mobSpawn;
+ }
+
+ function swordTraining {
+ speech(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("You chose the sword for this training, make sure to equip it or we can't start."));
+
+ speech(S_LAST_BLANK_LINE | S_NO_NPC_NAME,
+ l("I will place some dummies in the fighting arena. @@ waves of dummies, kill them to finish this training.", .maxWaves),
+ l("Ready?"));
+
+ askyesno;
+ if (@menu == ASK_NO)
+ {
+ closedialog;
+ end;
+ }
+
+ closedialog;
+ .fightingActive = 1;
+ initnpctimer;
+ }
+
+ function bowTraining {
+ speech(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("You chose the bow for this training, make sure to equip it or we can't start."));
+
+ speech(S_LAST_BLANK_LINE | S_NO_NPC_NAME,
+ l("I've set these dummies on fire. Don't get too close to the dummies or the fire will hurt you."),
+ l("The range of your bow makes it possible to kill them from a distance."),
+ l("Ready?"));
+
+ askyesno;
+ if (@menu == ASK_NO)
+ {
+ closedialog;
+ end;
+ }
+
+ .fightingActive = 2;
+ initnpctimer;
+ }
+
+ function skillTraining {
+
+ if (getq(.quest_training) == 3)
+ {
+ //Give bashing skill
+ skill(.skill_name, 1, 0);
+
+ speech(S_LAST_BLANK_LINE | S_NO_NPC_NAME,
+ l("Lets teach you the bashing skill. This is a very powerful way to hit your enemy by using only your bare hands."),
+ l("To use the skill you have to open your skills menu. Here you select the offensive tab and select the bash skill. When the bash skill is selected, press the use button the use the skill."));
+ }
+
+ speech(S_LAST_BLANK_LINE | S_NO_NPC_NAME,
+ l("You can only use this skill with bare hands, so make sure to unequip your weapons."),
+ l("@@ waves of dummies, you know how that ends.", .maxWaves),
+ l("Ready?"));
+
+ askyesno;
+ if (@menu == ASK_NO)
+ {
+ closedialog;
+ end;
+ }
+
+ .fightingActive = 3;
+ initnpctimer;
+ }
+
+ function checkCombatZone {
+
+ getmapxy('map$, @x, @y, 0);
+ if (@x < 24 || @x > 32 || @y < 33 || @y > 43)
+ return 1;
+ return 0;
+ }
+
+ // choose training and start it
+ function trainingStart {
+
+ if (checkCombatZone())
+ {
+ npctalk3(l("Please enter the combat zone on the left."));
+ closedialog;
+ end;
+ }
+ if (.fightingActive == 0)
+ {
+ switch (getq(.quest_training))
+ {
+ case 0: speech(S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("Which weapon do you want to train? Bow or sword?"));
+
+ switch (select(l("I'll start with the sword."),
+ l("I would like to train the bow first."),
+ l("I don't feel like training today, see you later.")))
+ {
+ case 1: swordTraining; break;
+ case 2: bowTraining; break;
+ case 3: closedialog; end;
+ }
+ break;
+ case 1: speech(S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("You have finished the sword training. Do you want to start training the bow?"));
+
+ switch (select(l("Yes, I'm ready for some arrow shooting!"),
+ l("Can I train the sword some more?"),
+ l("I don't feel like training today, see you later.")))
+ {
+ case 1: bowTraining; break;
+ case 2: swordTraining; break;
+ case 3: closedialog; end;
+ }
+ break;
+ case 2: speech(S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("You have finished the bow training. Do you want to start training the sword?"));
+
+ switch (select(l("Yes, teach me how to cut and slice these dummies!"),
+ l("Can I train the bow some more?"),
+ l("I don't feel like training today, see you later.")))
+ {
+ case 1: swordTraining; break;
+ case 2: bowTraining; break;
+ case 3: closedialog; end;
+ }
+ break;
+ case 3: speech(S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("You have mastered both the bow and the sword. The only thing left to teach you is the bashing skill."));
+
+ switch (select(l("A skill? That sounds useful!"),
+ l("Can I train the sword some more?"),
+ l("I would rather like to train the bow again."),
+ l("I don't feel like training today, see you later.")))
+ {
+ case 1: skillTraining; break;
+ case 2: swordTraining; break;
+ case 3: bowTraining; break;
+ case 4: closedialog; end;
+ }
+ break;
+ case 4: speech(S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE,
+ l("Sure, which training do you want to start?"));
+
+ switch (select(l("Skill training please"),
+ l("Can I train the sword some more?"),
+ l("I would like to train the bow again."),
+ l("I've changed my mind, see you later.")))
+ {
+ case 1: skillTraining; break;
+ case 2: swordTraining; break;
+ case 3: bowTraining; break;
+ case 4: closedialog; end;
+ }
+ break;
+ }
+ closedialog;
+
+ npctalk3(l("Let's begin"));
+
+ mobSpawn;
+ }
+ }
+
+ function mainLoop {
+
+ // if fighting is active say encouraging words to the player
+ if (.fightingActive != 0)
+ {
+ switch (.fightingActive)
+ {
+ case 1: npctalk3(l("Attack with your sword and kill them!")); end;
+ case 2: npctalk3(l("Use your bow and kill them!")); end;
+ case 3: npctalk3(l("Hey lazy bum! Attack the dummies")); end;
+ default: break;
+ }
+ }
+
+ // only start if player talked with Lozerk and is not an enemy
+ if (getq(Artis_Legion_Progress) < 1 || faction_standing("LEGION", true) < 1)
+ {
+ speech(S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("This is the training ground. And I ain't training nobody unless Lieutenant Lozerk tells me to!"),
+ l("So please get out!"));
+ closedialog;
+ end;
+ }
+ else
+ {
+ switch (getq(.quest_training))
+ {
+ case 0: speech(S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l(.mockingGreeting$[rand(getarraysize(.mockingGreeting$))]),
+ l("Do you want some training? To be honest, it looks like you could use some..."));
+ break;
+ case 4: speech(S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Your training is finished, I taught you all I know."),
+ l("So now go and explore the world!"));
+ switch (select(
+ l("Can I first have an other look at your book?"),
+ l("Before doing that can I improve my fighting skills some more?"),
+ l("Okay!")))
+ {
+ case 1: doevent("#EvolTutorial::OnRemoteHelp");; break;
+ case 2: trainingStart; break;
+ case 3: closedialog; end;
+ }
+ closedialog;
+ end;
+ default: speech(S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Hello again, ready to continue your lessons?")); break;
+ }
+
+ do
+ {
+ selectd(
+ l("Yes, train me!"),
+ l("Hmm... But what is exactly this training?"),
+ l("I'm a bit lost in this game, can you first give me few tips?"),
+ l("Not right now, it looks like I got other stuff to do."));
+
+ switch (@menu)
+ {
+ case 1: trainingStart; break;
+ case 2:
+ // here text who explain what is the training of this npc
+ speech(S_FIRST_BLANK_LINE | S_LAST_NEXT | S_LAST_BLANK_LINE | S_NO_NPC_NAME,
+ l("In this training, my goal is to teach you how to be a skilled warrior, who can use a sword, a bow and a skill."),
+ l("For this, you need a sword and a bow."),
+ l("After you gathered your weapons, I will teach you how to use them."));
+ break;
+ case 3:
+ speech(S_FIRST_BLANK_LINE | S_LAST_NEXT | S_LAST_BLANK_LINE | S_NO_NPC_NAME,
+ l("I have a book with all the info you need, do you want to read it?"));
+ askyesno;
+ if (@menu == ASK_YES)
+ {
+ doevent("#EvolTutorial::OnRemoteHelp");
+ closedialog;
+ end;
+ }
+ break;
+ case 4: closedialog; end;
+
+ default: closedialog; end;
+ }
+ } while (1);
+ }
+ }
+
+ mainLoop;
+ closedialog;
+ end;
+
+OnTimer1000:
+ if (.fightingActive != 0)
+ {
+ if (checkCombatZone())
+ {
+ npctalk3(l("You left the combat zone!"));
+ trainingEnd;
+ }
+ checkWeapon;
+ initnpctimer;
+ }
+ end;
+
+OnTrainingMobDead:
+ // the amount of mob spawned depend on currentwave
+ if (++'mobDead == .currentWaveLevel)
+ {
+ mobKilled;
+ }
+ end;
+
+OnInit:
+ .mana_potion = LargeMana;
+ .skill_name = SM_BASH;
+ .quest_training = ArtisQuests_TrainingLegion;
+ .quest_debug = .quest_training;
+ .maxWaves = 3;
+
+ .currentWaveLevel = 1;
+ .fightingActive = 0;
+
+ // TODO FIXME translation
+ // here input some sentences "hello noob" like, the npc pick randomly a sentence
+ setarray .mockingGreeting$[0], "Hey noob!", "Hey somethingwholooklikeawarrior...", "Sup' chibi.";
+ setarray .mobID[0],0, Dummy, FireDummy, Dummy; // an array of dummies, one for each training
+ setarray .mobCoordinate[0], 24, 34, 31, 41; // this represent the square of "ring" training
+
+ end;
+
+}
diff --git a/npc/001-2-36/mapflags.txt b/npc/001-2-36/mapflags.txt
new file mode 100644
index 00000000..457bc70e
--- /dev/null
+++ b/npc/001-2-36/mapflags.txt
@@ -0,0 +1 @@
+001-2-36 mapflag town
diff --git a/npc/001-2-37/_import.txt b/npc/001-2-37/_import.txt
new file mode 100644
index 00000000..03162e19
--- /dev/null
+++ b/npc/001-2-37/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-37: Legion West Wing
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-37/_savepoints.txt",
+"npc/001-2-37/_warps.txt",
+"npc/001-2-37/hammock.txt",
+"npc/001-2-37/mapflags.txt",
diff --git a/npc/001-2-37/_savepoints.txt b/npc/001-2-37/_savepoints.txt
new file mode 100644
index 00000000..30d7a797
--- /dev/null
+++ b/npc/001-2-37/_savepoints.txt
@@ -0,0 +1,54 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-37: Legion West Wing saves
+001-2-37,25,41,0 script #save_001-2-37_25_41 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-37,35,41,0 script #save_001-2-37_35_41 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-37,35,46,0 script #save_001-2-37_35_46 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-37,25,46,0 script #save_001-2-37_25_46 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-37/_warps.txt b/npc/001-2-37/_warps.txt
new file mode 100644
index 00000000..dabc5285
--- /dev/null
+++ b/npc/001-2-37/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-37: Legion West Wing warps
+001-2-37,37,28,0 warp #001-2-37_37_28 0,0,001-2-33,24,30
+001-2-37,37,33,0 warp #001-2-37_37_33 0,0,001-2-39,24,33
diff --git a/npc/001-2-37/hammock.txt b/npc/001-2-37/hammock.txt
new file mode 100644
index 00000000..c749217a
--- /dev/null
+++ b/npc/001-2-37/hammock.txt
@@ -0,0 +1,106 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Animated hammock at the top left level of the Legion of Aemil
+// building of Artis.
+
+001-2-37,26,26,0 script #001-2-37hammock0 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-37,25,28,0 script #001-2-37hammock1 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-37,25,30,0 script #001-2-37hammock2 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-37,25,32,0 script #001-2-37hammock3 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-37,29,26,0 script #001-2-37hammock4 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-37,29,28,0 script #001-2-37hammock5 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-37,29,30,0 script #001-2-37hammock6 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-37,29,32,0 script #001-2-37hammock7 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-37,25,34,0 script #001-2-37hammock8 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-37,26,36,0 script #001-2-37hammock9 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
diff --git a/npc/001-2-37/mapflags.txt b/npc/001-2-37/mapflags.txt
new file mode 100644
index 00000000..c4f939b4
--- /dev/null
+++ b/npc/001-2-37/mapflags.txt
@@ -0,0 +1 @@
+001-2-37 mapflag town
diff --git a/npc/001-2-38/_import.txt b/npc/001-2-38/_import.txt
new file mode 100644
index 00000000..63d2a402
--- /dev/null
+++ b/npc/001-2-38/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-38: Legion East Wing
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-38/_savepoints.txt",
+"npc/001-2-38/_warps.txt",
+"npc/001-2-38/hammock.txt",
+"npc/001-2-38/mapflags.txt",
diff --git a/npc/001-2-38/_savepoints.txt b/npc/001-2-38/_savepoints.txt
new file mode 100644
index 00000000..59be0f59
--- /dev/null
+++ b/npc/001-2-38/_savepoints.txt
@@ -0,0 +1,54 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-38: Legion East Wing saves
+001-2-38,25,41,0 script #save_001-2-38_25_41 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-38,35,41,0 script #save_001-2-38_35_41 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-38,35,46,0 script #save_001-2-38_35_46 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+001-2-38,25,46,0 script #save_001-2-38_25_46 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/001-2-38/_warps.txt b/npc/001-2-38/_warps.txt
new file mode 100644
index 00000000..53e119b5
--- /dev/null
+++ b/npc/001-2-38/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-38: Legion East Wing warps
+001-2-38,23,28,0 warp #001-2-38_23_28 0,0,001-2-33,44,30
+001-2-38,23,33,0 warp #001-2-38_23_33 0,0,001-2-39,44,33
diff --git a/npc/001-2-38/hammock.txt b/npc/001-2-38/hammock.txt
new file mode 100644
index 00000000..2c8938da
--- /dev/null
+++ b/npc/001-2-38/hammock.txt
@@ -0,0 +1,106 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Animated hammock at the top right level of the Legion of Aemil
+// building of Artis.
+
+001-2-38,31,26,0 script #001-2-38hammock0 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-38,31,28,0 script #001-2-38hammock1 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-38,31,30,0 script #001-2-38hammock2 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-38,31,32,0 script #001-2-38hammoc3 NPC_LEFT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchLeft;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerLeft;
+}
+
+001-2-38,34,26,0 script #001-2-38hammock4 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-38,35,28,0 script #001-2-38hammock5 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-38,35,30,0 script #001-2-38hammock6 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-38,35,32,0 script #001-2-38hammock7 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-38,35,34,0 script #001-2-38hammock8 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
+
+001-2-38,34,36,0 script #001-2-38hammock9 NPC_RIGHT_HAMMOCK,1,0,{
+
+OnTouch: hamTouchRight;
+
+OnUnTouch: hamUnTouch;
+
+OnTimer5440:
+ hamTimerRight;
+}
diff --git a/npc/001-2-38/mapflags.txt b/npc/001-2-38/mapflags.txt
new file mode 100644
index 00000000..8a5c5d4e
--- /dev/null
+++ b/npc/001-2-38/mapflags.txt
@@ -0,0 +1 @@
+001-2-38 mapflag town
diff --git a/npc/001-2-39/_import.txt b/npc/001-2-39/_import.txt
new file mode 100644
index 00000000..f3a2043a
--- /dev/null
+++ b/npc/001-2-39/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-39: Legion Command Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-39/_warps.txt",
+"npc/001-2-39/mapflags.txt",
+"npc/001-2-39/qanon.txt",
diff --git a/npc/001-2-39/_warps.txt b/npc/001-2-39/_warps.txt
new file mode 100644
index 00000000..1a25cfd3
--- /dev/null
+++ b/npc/001-2-39/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-39: Legion Command Room warps
+001-2-39,45,33,0 warp #001-2-39_45_33 0,0,001-2-38,24,33
+001-2-39,23,33,0 warp #001-2-39_23_33 0,0,001-2-37,36,33
diff --git a/npc/001-2-39/mapflags.txt b/npc/001-2-39/mapflags.txt
new file mode 100644
index 00000000..5d688785
--- /dev/null
+++ b/npc/001-2-39/mapflags.txt
@@ -0,0 +1 @@
+001-2-39 mapflag town
diff --git a/npc/001-2-39/qanon.txt b/npc/001-2-39/qanon.txt
new file mode 100644
index 00000000..e0c8d26b
--- /dev/null
+++ b/npc/001-2-39/qanon.txt
@@ -0,0 +1,131 @@
+// Evol scripts.
+// Authors:
+// Alige
+// Reid
+// Jesusalva
+// Description:
+// Artis's Legion of Aemil leader.
+// Variables:
+// Artis_Legion_Progress
+// Values:
+// 5 Sent by Lozerk.
+// 6 Train forever (Cannot resume legion, must see brotherhood first)
+// Technically, Q'Anon wants to see if player will recover his memory.
+// After all, player memories might have something important.
+// 7 Arrived at Hurnscald (This means we can resume legion)
+
+001-2-39,34,41,0 script Q'Anon NPC_Q_ANON,{
+ function legionState;
+ function legionState2;
+ function notaMember;
+ .@q=getq(Artis_Legion_Progress);
+ mesn;
+ mesq l("It's been a while.");
+ next;
+ if (.@q < 5)
+ notaMember();
+
+ // Faction report
+ mesc l("Your current standing with the Legion: %s", faction_standing("LEGION", false));
+ if (LEGION_RANK)
+ mesc l("You are a Legion's %s", legionrank());
+
+ // Main Menu
+ select
+ rif(.@q == 5, l("Lozerk told me to talk to you and join the legion.")),
+ rif(.@q == 6, l("Have I grown enough reputation to join?")),
+ l("Thanks, sir Q'Anon.");
+ mes "";
+ switch (@menu)
+ {
+ case 1:
+ legionState();
+ break;
+ case 2:
+ legionState2();
+ break;
+ case 3:
+ mesn;
+ mesq l("Make me proud!");
+ break;
+ }
+ close;
+
+function notaMember {
+ mesn;
+ mesq col(l("*ahem*"), 9) + " " + l("Heh, did you saw me at the port? No?");
+ next;
+ mesn;
+ mesq l("This is how good we Legion Members are. I was informed of your arrival way before you left Drasil Island.");
+ next;
+ mesn;
+ mesq l("I usually would not care, but it is not every day a complete stranger arrives at Artis.");
+ next;
+ mesn;
+ mesq l("You're welcome to stay here as long as you wish. Just don't do anything stupid, like a riot, for example.");
+ close;
+ return;
+}
+
+function legionState {
+ mesn;
+ mesq l("Oh? And do you think you have what it takes to be a proud Legion Member?");
+ next;
+ mesn;
+ mesq l("Listen, kid. Being a legion member is not a joke.");
+ next;
+ mesn;
+ mesq l("Hmm, why don't you go train a little more? We have several training rooms here.");
+ next;
+ mesn;
+ mesq l("Yes, I am authorizing you to use them as you deem fit, until you get stronger.");
+ next;
+ mesn;
+ mesq l("Also, build a reputation with the Legion. Talk to everyone. Help everyone. Prove me your worth!");
+ next;
+ mesn;
+ mesq l("Only after you prove yourself, you may join our ranks as a proud member! Hahah!");
+ setq Artis_Legion_Progress, 6;
+ // So, we probably should use Clan System for the major guilds.
+ // I guess major guilds are: Legion, Brotherhood
+ // minor guilds: Merchants, Thieves and Mages.
+
+ // It would be the commands below:
+ // join_clan(FACTION_LEGION);
+ // clan_leave();
+ return;
+}
+
+function legionState2 {
+ if (faction_standing("LEGION", true) >= 1) {
+ mesn;
+ mesq l("Actually. I am thinking in sending you in a... special mission.");
+ next;
+ mesn;
+ mesq l("You probably noticed a frigate docked near La Johanne when you arrived?");
+ next;
+ mesn;
+ mesq l("We've found... the old continent, from where our race came from long ago.");
+ next;
+ mesn;
+ mesq l("It seems to have fallen in barbarian hands since the Fleet of Ancea, and that, is not something we can allow.");
+ next;
+ mesn;
+ mesc l("%s gives you a piece of paper, which you put on a different pocket.");
+ mesq l("Go to the ship, show the captain this letter if asked. After reaching, look for Captain Hal. He'll give you further instructions.");
+ next;
+ mesn;
+ mesq l("Make me proud!");
+ setq Artis_Legion_Progress, 7;
+ } else {
+ mesn;
+ mesq l("Hmm... No, not yet. Try helping other legion members around.");
+ }
+ return;
+}
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/001-2-4/_import.txt b/npc/001-2-4/_import.txt
new file mode 100644
index 00000000..70c629cc
--- /dev/null
+++ b/npc/001-2-4/_import.txt
@@ -0,0 +1,7 @@
+// Map 001-2-4: Library
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-4/_warps.txt",
+"npc/001-2-4/books.txt",
+"npc/001-2-4/mapflags.txt",
+"npc/001-2-4/robin.txt",
+"npc/001-2-4/terry.txt",
diff --git a/npc/001-2-4/_warps.txt b/npc/001-2-4/_warps.txt
new file mode 100644
index 00000000..73e39877
--- /dev/null
+++ b/npc/001-2-4/_warps.txt
@@ -0,0 +1,27 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-4: Library warps
+001-2-4,48,41,0 warp #001-2-4_48_41 0,0,001-1,51,81
+001-2-4,57,27,0 warp #001-2-4_57_27 3,0,001-2-6,57,36
+001-2-4,52,27,0 script #001-2-4_52_27_h NPC_HIDDEN,0,0,{
+OnTouch:
+ warp "001-2-5", 28, 37;
+close;
+
+OnUnTouch:
+ doevent "#001-2-4_52_27::OnUnTouch";
+}
+001-2-4,52,27,0 script #001-2-4_52_27 NPC_ARTIS_IN_DOOR,3,3,{
+ close;
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ doorInit;
+}
+
diff --git a/npc/001-2-4/books.txt b/npc/001-2-4/books.txt
new file mode 100644
index 00000000..96f9ae5e
--- /dev/null
+++ b/npc/001-2-4/books.txt
@@ -0,0 +1,102 @@
+// Evol scripts.
+// Author:
+// gumi
+// Tirifto
+// Description:
+// moar books
+
+001-2-4,28,29,0 script #001-2-4-Book1 NPC_NO_SPRITE,{
+
+ doevent "@rules::OnShelfUse";
+ close;
+
+OnInit:
+ .distance = 1;
+}
+
+// FIXME: we need a no-sprite npc that is offset 1 tile north
+001-2-4,47,28,0 script #001-2-4-Book2 NPC_NO_SPRITE,{
+
+ function read_book {
+
+ setnpcdialogtitle l(.book_name$);
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("To get started with fishing, you'll need two things: a fishing rod and a bait."),
+ l("You just need one fishing rod, although you should take more than one single bait.");
+
+ @menu = 0; // reset for the rif
+
+ do
+ {
+ narrator S_NO_NPC_NAME,
+ l("Please select a chapter:");
+
+ mes "";
+
+ select
+ rif(@menu == 1, "► ") + l("Ch 1 — Fishing apparatus"),
+ rif(@menu == 2, "► ") + l("Ch 2 — Baits"),
+ rif(@menu == 3, "► ") + l("Ch 3 — Location"),
+ rif(@menu == 4, "► ") + l("Ch 4 — Casting"),
+ rif(@menu == 5, "► ") + l("Ch 5 — Reeling");
+
+ switch(@menu)
+ {
+ case 1:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You'll want your fishing rod to be flexible but solid."),
+ l("Comfortable grip is important especially for newcomers, since they'll be holding it for quite a while.");
+ break;
+ case 2:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You can use many diverse items to lure fishes."),
+ l("Some people prefer to catch fish using magic, but calling that \"fishing\" would be an insult to this traditional sport."),
+ l("Most common and widely popular in the fish realm are @@ and pieces of @@.",
+ getitemlink(SmallTentacles), getitemlink(Bread)),
+ l("Some types of fish also enjoy @@ quite a bit.",
+ getitemlink(Aquada)),
+ l("Some people, however, prefer to fish with more unorthodox baits, such as @@ or @@.",
+ getitemlink(UrchinMeat), getitemlink(TortugaTongue));
+ break;
+ case 3:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Find yourself a nice dry spot on a coast where you can easily reach into deep water."),
+ l("Fishing next to shallow water is not going to work well, because fishes seldom go there."),
+ l("You can easily identify fishing spots, small bubbles and fishes are visible from the surface."),
+ l("Don't forget to come as close as possible to these spots!");
+ break;
+ case 4:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Toss the hook into deep water by clicking on where you want to cast it."),
+ l("Make sure to put on a bait after you click, though!"),
+ l("After that, stay still and be patient, but also alert!");
+ break;
+ case 5:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("To successfully catch a fish, you need to pull up your hook by clicking it, right after it submerges."),
+ l("Should you be too quick or wait too long, you will most likely fail.");
+ break;
+ }
+ } while (true);
+
+ end;
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = getitemname(FishingGuideVolI);
+ .distance = 1;
+ end;
+}
diff --git a/npc/001-2-4/mapflags.txt b/npc/001-2-4/mapflags.txt
new file mode 100644
index 00000000..1a66f670
--- /dev/null
+++ b/npc/001-2-4/mapflags.txt
@@ -0,0 +1 @@
+001-2-4 mapflag town
diff --git a/npc/001-2-4/robin.txt b/npc/001-2-4/robin.txt
new file mode 100644
index 00000000..6b4cf24f
--- /dev/null
+++ b/npc/001-2-4/robin.txt
@@ -0,0 +1,64 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Librarian
+
+001-2-4,27,33,0 script Robin NPC_ROBIN,{
+
+ function need_help
+ {
+ speech S_LAST_NEXT,
+ l("Do you need help with something?");
+
+ switch (select(l("What kinds of books are there here?"),
+ l("Nothing.")))
+ {
+ case 1:
+ closeclientdialog;
+ npctalk3 l("Mostly manuals and tutorials but you won't find out until you open one!");
+ break;
+ case 2:
+ closeclientdialog;
+ npctalk3 l("Good day to you!");
+ }
+ return;
+ }
+
+
+ switch (rand(6))
+ {
+ case 0:
+ npctalkonce l("No matter what people tell you, words and ideas can change the world.");
+ break;
+ case 1:
+ npctalkonce l("In Artis they really do mythologize people when they die.");
+ break;
+ case 2:
+ npctalkonce l("What counts in a book is like so many things, not what is on the outside, but what is on the inside.");
+ break;
+ case 3:
+ npctalkonce l("An explorer left behind some incomplete manuscripts about the people and dangers in the land of Kaizei.");
+ break;
+ case 4:
+ speech S_LAST_NEXT,
+ l("Ow-oh!"),
+ l("Introduce yourself instead of poking me around. I almost fell from the lader, savage...");
+
+ setcamnpc "#001-2-4-Book1";
+
+ speech S_NO_NPC_NAME,
+ l("Go have a look at that shelf to my right, would you?"),
+ l("You clearly need to be more public-spirited.");
+ break;
+ default:
+ need_help;
+ break;
+ }
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-4/terry.txt b/npc/001-2-4/terry.txt
new file mode 100644
index 00000000..ec13c53e
--- /dev/null
+++ b/npc/001-2-4/terry.txt
@@ -0,0 +1,15 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Librarian
+
+001-2-4,51,35,2 script Terry NPC_TERRY,{
+ mesn;
+ mesq l("Hi.");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-40/_import.txt b/npc/001-2-40/_import.txt
new file mode 100644
index 00000000..c8363c34
--- /dev/null
+++ b/npc/001-2-40/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-40: Legion Basement
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-40/_warps.txt",
+"npc/001-2-40/mapflags.txt",
+"npc/001-2-40/trozz.txt",
diff --git a/npc/001-2-40/_warps.txt b/npc/001-2-40/_warps.txt
new file mode 100644
index 00000000..6a2994d5
--- /dev/null
+++ b/npc/001-2-40/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-40: Legion Basement warps
+001-2-40,45,44,0 warp #001-2-40_45_44 2,0,001-2-33,43,39
+001-2-40,27,44,0 warp #001-2-40_27_44 2,0,001-2-33,25,39
+001-2-40,56,41,0 warp #001-2-40_56_41 0,0,001-3-0,56,44
diff --git a/npc/001-2-40/mapflags.txt b/npc/001-2-40/mapflags.txt
new file mode 100644
index 00000000..0c9303e8
--- /dev/null
+++ b/npc/001-2-40/mapflags.txt
@@ -0,0 +1 @@
+001-2-40 mapflag town
diff --git a/npc/001-2-40/trozz.txt b/npc/001-2-40/trozz.txt
new file mode 100644
index 00000000..b96166d3
--- /dev/null
+++ b/npc/001-2-40/trozz.txt
@@ -0,0 +1,66 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Chief of the Legion of Aemil of the city of Artis.
+
+001-2-40,36,46,0 script Trozz#001-2-40 NPC_HUMAN_MALE_CHIEF_ARTIS_LEGION,{
+ function Bureaucracy;
+ function Dueling;
+ mesn;
+ mesq l("Hi. I am Trozz, and I am the chief of legion training in Artis.");
+ next;
+ mesn;
+ mesq l("If you want to challenge someone for a friendly match, you are at the right place.");
+ next;
+ do
+ {
+ select
+ l("That's everything, thanks."),
+ l("I'm looking to have some paperwork fixed."),
+ l("How can I challenge someone for a match?");
+ mes "";
+ switch (@menu) {
+ case 1:
+ goodbye();
+ break;
+ case 2:
+ Bureaucracy();
+ break;
+ case 3:
+ Dueling();
+ break;
+ }
+ } while (@menu != 1);
+ close;
+
+function Bureaucracy {
+ mesn;
+ mesq l("If you need to deal with more bureaucratic stuff, go talk to Q'Anon. He is the boss here.");
+ next;
+ mesn;
+ mesq l("You can find him upstairs. Go left, then go right, and you'll find him.");
+ next;
+ return;
+}
+
+function Dueling {
+ mesn;
+ mesq l("First, you need to use %s to enter in duel mode.", b("@duel"));
+ next;
+ mesn;
+ mesq l("Then, to challenge a player, you'll use \"%s <player_name>\".", b("@invite"));
+ next;
+ mesn;
+ mesq l("If you were invited to the duel instead, you can use %s or %s.", b("@accept"), b("@reject"));
+ next;
+ mesn;
+ mesq l("You can exit duel mode with %s. You'll also leave it by death.", b("@leave"));
+ next;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/001-2-41/_import.txt b/npc/001-2-41/_import.txt
new file mode 100644
index 00000000..1584e4d6
--- /dev/null
+++ b/npc/001-2-41/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-41: Barber
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-41/_warps.txt",
+"npc/001-2-41/edouard.txt",
+"npc/001-2-41/mapflags.txt",
diff --git a/npc/001-2-41/_warps.txt b/npc/001-2-41/_warps.txt
new file mode 100644
index 00000000..76251c2a
--- /dev/null
+++ b/npc/001-2-41/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-41: Barber warps
+001-2-41,24,32,0 warp #001-2-41_24_32 0,0,001-2-31,35,32
diff --git a/npc/001-2-41/edouard.txt b/npc/001-2-41/edouard.txt
new file mode 100644
index 00000000..275896e3
--- /dev/null
+++ b/npc/001-2-41/edouard.txt
@@ -0,0 +1,175 @@
+// Evol scripts.
+// Authors:
+// Reid
+// Travolta
+// Description:
+// Barber of Aemil
+
+function script EdouardCheckChair {
+
+ getmapxy(.@map$, .@x, .@y, UNITTYPE_PC);
+
+ if ((.@map$ != getarg(0)) || (.@x != getarg(1)) || (.@y != getarg(2)))
+ {
+ doevent "Edouard::OnWrongPlace";
+ }
+ else if (!issit())
+ {
+ doevent "Edouard::OnNotSit";
+ }
+ else
+ {
+ doevent "Edouard::OnChair";
+ }
+
+ close;
+}
+
+001-2-41,29,24,0 script Chair#Chair1-001-2-41 NPC_NO_SPRITE,{
+
+ EdouardCheckChair .map$, .x, .y;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-41,31,24,0 script Chair#Chair2-001-2-41 NPC_NO_SPRITE,{
+
+ EdouardCheckChair .map$, .x, .y;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-41,35,27,0 script Chair#Chair3-001-2-41 NPC_NO_SPRITE,{
+
+ EdouardCheckChair .map$, .x, .y;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-41,35,29,0 script Chair#Chair4-001-2-41 NPC_NO_SPRITE,{
+
+ EdouardCheckChair .map$, .x, .y;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-41,35,35,0 script Chair#Chair5-001-2-41 NPC_NO_SPRITE,{
+
+ EdouardCheckChair .map$, .x, .y;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-41,35,37,0 script Chair#Chair6-001-2-41 NPC_NO_SPRITE,{
+
+ EdouardCheckChair .map$, .x, .y;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-41,30,29,0 script Edouard NPC_EDOUARD,{
+ function tellStory;
+ //EdouardCheckChair();
+ if (!issit())
+ goto OnWrongPlace;
+ // Disregard if you're in the chair or not, for sake of gameplay
+ goto OnChair;
+
+function tellStory {
+ if (Edouard_StoryTold != 0)
+ {
+ mes "";
+ mesn;
+ }
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("I am new in this town, just like you."),
+ l("I came here, looking for a better life."),
+ l("And so far, the Merchant Guild helped me find this appartment so I can't complain!"),
+ l("Anyway."),
+ l("I'm a barber, you see. I can change your hairstyle or hair color to your current taste.");
+
+ Edouard_StoryTold = 1;
+
+ return;
+}
+
+OnWrongPlace:
+ npctalkonce("Sit on the chair, I will come in a second!");
+ close;
+
+OnNotSit:
+ npctalkonce("Please sit.");
+ close;
+
+OnChair:
+ speech S_LAST_NEXT,
+ l("Welcome to Edouard's Barber Shop.");
+
+ if (Edouard_StoryTold == 0)
+ {
+ tellStory;
+ }
+
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("What would you like me to do?");
+
+ do
+ {
+ select
+ l("What is my current hairstyle and hair color?"),
+ l("I'd like to get a different style."),
+ l("Can you do something with my color?"),
+ l("How about changing my body type?"),
+ l("What's your story again?"),
+ l("I'm fine for now, thank you.");
+
+ switch (@menu)
+ {
+ case 1:
+ BarberSayStyle();
+ break;
+ case 2:
+ BarberChangeStyle;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Enjoy your new style."),
+ l("Anything else?");
+ break;
+ case 3:
+ BarberChangeColor;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I hope you like this color."),
+ l("Anything else?");
+ break;
+ case 4:
+ BarberChangeBodyType();
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You look fantastic."),
+ l("Anything else?");
+ break;
+ case 5:
+ tellStory;
+ break;
+ case 6:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Feel free to come visit me another time.");
+
+ goodbye;
+ }
+ } while (1);
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-41/mapflags.txt b/npc/001-2-41/mapflags.txt
new file mode 100644
index 00000000..eb1b712b
--- /dev/null
+++ b/npc/001-2-41/mapflags.txt
@@ -0,0 +1 @@
+001-2-41 mapflag town
diff --git a/npc/001-2-42/_import.txt b/npc/001-2-42/_import.txt
new file mode 100644
index 00000000..1afffd48
--- /dev/null
+++ b/npc/001-2-42/_import.txt
@@ -0,0 +1,3 @@
+// Map 001-2-42: Docks Warehouse Second Level
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-42/_warps.txt",
diff --git a/npc/001-2-42/_warps.txt b/npc/001-2-42/_warps.txt
new file mode 100644
index 00000000..d8b06045
--- /dev/null
+++ b/npc/001-2-42/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-42: Docks Warehouse Second Level warps
+001-2-42,39,37,0 warp #001-2-42_39_37 2,0,001-2-18,39,28
diff --git a/npc/001-2-43/_import.txt b/npc/001-2-43/_import.txt
new file mode 100644
index 00000000..ed7173e0
--- /dev/null
+++ b/npc/001-2-43/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-43: Archive
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-43/_warps.txt",
+"npc/001-2-43/core.txt",
+"npc/001-2-43/mapflags.txt",
diff --git a/npc/001-2-43/_warps.txt b/npc/001-2-43/_warps.txt
new file mode 100644
index 00000000..2a53a67d
--- /dev/null
+++ b/npc/001-2-43/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-43: Archive warps
+001-2-43,51,35,0 warp #001-2-43_51_35 2,0,001-3-0,90,62
diff --git a/npc/001-2-43/core.txt b/npc/001-2-43/core.txt
new file mode 100644
index 00000000..f30e3828
--- /dev/null
+++ b/npc/001-2-43/core.txt
@@ -0,0 +1,147 @@
+// Evol scripts.
+// Author:
+// Micksha, Jesusalva
+// Description:
+// Core of Henry's Quest
+
+001-2-43,25,24,0 script #ArtisThiefBook_1 NPC_NO_SPRITE,{
+ .@q=getq(ThiefQuests_Artis);
+ .@q3=getq3(ThiefQuests_Artis);
+
+ // Add a forced delay to prevent abuse
+ if (.@q != 1) end;
+ getmapxy(.@m$, @x, @y, 0); // Save in @x/@y
+ dispbottom l("Sec, lemme look this.");
+ addtimer 1000, .name$+"::OnRead";
+ end;
+
+OnRead:
+ // Prepare the Quest Variables
+ .@q=getq(ThiefQuests_Artis);
+ .@q3=getq3(ThiefQuests_Artis);
+
+ // You must not have moved
+ getmapxy(.@m$, .@x, .@y, 0);
+ if (.@x != @x || .@y != @y || .@q != 1) {
+ dispbottom l("I'm so busy, I can look there later.");
+ end;
+ }
+
+ // Clear temporary variables
+ @x=@y=0;
+
+ // Extract the quest ID from name (or fail trying)
+ explode(.@ni$, .name$, "_");
+ .@id=atoi(.@ni$[1]);
+
+ // Check if the file was here
+ if (.@q3 == .@id) {
+ // TODO: Dialog: How will you deal with the file?
+ // .@t$=faction_addrep("Legion", 50)
+ // .@t$=faction_addrep("Thief", 50)
+ // mesc .@t$;
+ mes l("This is it - Henry's files!");
+ mes l("I need to decide swiftly what I'll do with them before I'm caught.");
+ mesc l("This decision will be remembered."), 1;
+ next;
+ select
+ l("Hide the file below the pots"),
+ l("[Legion+] [Thieves-] Highlight the file"),
+ l("[Legion-] [Thieves+] Destroy the file");
+ mes "";
+ switch (@menu) {
+ case 2:
+ .@t$=faction_addrep("Legion", 50);
+ mesc .@t$;
+ .@t$=faction_addrep("Thief", -50);
+ mesc .@t$;
+ next;
+ break;
+ case 3:
+ .@t$=faction_addrep("Legion", -50);
+ mesc .@t$;
+ .@t$=faction_addrep("Thief", 50);
+ mesc .@t$;
+ next;
+ break;
+ }
+ dispbottom l("You notice by chance that the file does not have any picture on it.");
+ setq ThiefQuests_Artis, 2, 0, 0;
+ closeclientdialog;
+ } else {
+ dispbottom l("Not here, lets look elsewhere!");
+ }
+ end;
+
+OnInit:
+ .distance=1;
+ end;
+}
+
+// Duplicate the town files
+001-2-43,24,28,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_2 NPC_NO_SPRITE
+001-2-43,25,32,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_4 NPC_NO_SPRITE
+001-2-43,29,28,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_8 NPC_NO_SPRITE
+001-2-43,34,32,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_16 NPC_NO_SPRITE
+001-2-43,38,32,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_32 NPC_NO_SPRITE
+001-2-43,44,32,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_64 NPC_NO_SPRITE
+001-2-43,48,32,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_128 NPC_NO_SPRITE
+001-2-43,48,28,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_256 NPC_NO_SPRITE
+001-2-43,43,28,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_512 NPC_NO_SPRITE
+001-2-43,38,28,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_1024 NPC_NO_SPRITE
+001-2-43,33,28,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_2048 NPC_NO_SPRITE
+001-2-43,53,24,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_4096 NPC_NO_SPRITE
+001-2-43,44,24,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_8192 NPC_NO_SPRITE
+001-2-43,29,24,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_16384 NPC_NO_SPRITE
+001-2-43,39,24,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_32768 NPC_NO_SPRITE
+001-2-43,49,24,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_65536 NPC_NO_SPRITE
+// Fail-safe; Henry's record should not be here
+001-2-43,34,24,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_131072 NPC_NO_SPRITE
+//001-2-43,29,31,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_131072 NPC_NO_SPRITE
+//001-2-43,24,26,0 duplicate(#ArtisThiefBook_1) #ArtisThiefBook_262144 NPC_NO_SPRITE
+
+
+// Logical Handler
+001-2-43,0,0,0 script #ArtisThiefBook_0 NPC_HIDDEN,{
+ end;
+OnBust1:
+ if (getmap() != .map$)
+ end;
+ dispbottom col(l("90 seconds remaining."), 1);
+ addtimer 30000, "#ArtisThiefBook_0::OnBust2";
+ end;
+
+OnBust2:
+ if (getmap() != .map$)
+ end;
+ dispbottom col(l("60 seconds remaining."), 1);
+ addtimer 30000, "#ArtisThiefBook_0::OnBust3";
+ end;
+
+OnBust3:
+ if (getmap() != .map$)
+ end;
+ dispbottom col(l("30 seconds remaining."), 1);
+ addtimer 30000, "#ArtisThiefBook_0::OnBust4";
+ end;
+
+OnBust4:
+ if (getmap() == .map$) {
+ // Warp you elsewhere before actually arresting
+ // Otherwise, you would return at Archives without this timer =/
+ warp "001-1", 90, 55;
+ sleep2(10);
+
+ // Check if you'll be caught
+ if (ArrestedChances()) {
+ mesc l("Arrested!");
+ mesc l("You'll now spend a few minutes on the jail to reflect on your actions.");
+ ArrestPlayer(5);
+ } else {
+ mesc l("You're almost found out, but manage to make a quick escape!");
+ warp "001-1", 90, 55;
+ }
+ }
+ close;
+}
+
diff --git a/npc/001-2-43/mapflags.txt b/npc/001-2-43/mapflags.txt
new file mode 100644
index 00000000..d32035bb
--- /dev/null
+++ b/npc/001-2-43/mapflags.txt
@@ -0,0 +1 @@
+001-2-43 mapflag nosave 001-1,89,67
diff --git a/npc/001-2-5/_import.txt b/npc/001-2-5/_import.txt
new file mode 100644
index 00000000..58c8fbb9
--- /dev/null
+++ b/npc/001-2-5/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-2-5: Warehouse
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-5/_warps.txt",
+"npc/001-2-5/books.txt",
+"npc/001-2-5/mapflags.txt",
+"npc/001-2-5/tutorial.txt",
diff --git a/npc/001-2-5/_warps.txt b/npc/001-2-5/_warps.txt
new file mode 100644
index 00000000..7d543143
--- /dev/null
+++ b/npc/001-2-5/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-5: Warehouse warps
+001-2-5,28,38,0 warp #001-2-5_28_38 0,0,001-2-4,52,29
diff --git a/npc/001-2-5/books.txt b/npc/001-2-5/books.txt
new file mode 100644
index 00000000..fc5e3abe
--- /dev/null
+++ b/npc/001-2-5/books.txt
@@ -0,0 +1,33 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Gasaron
+
+001-2-5,30,32,0 script #001-2-5-Book1 NPC_NO_SPRITE,{
+
+ function read_book {
+ narrator S_FIRST_BLANK_LINE,
+ l("There are two kinds of dialogue, the ones with regular citizens, and the ones with other adventurers."),
+ l("When you go near villagers, you can see a speech bubble above them, you can then talk to them by pressing the [T] key."),
+ l("You can select a specific person with the [N] key, and then, press the [T] key when you are surrounded by more than one person."),
+ l("You can also simply talk to any citizen around you by clicking on them."),
+ l("Nevertheless, you can talk with another adventurer by pressing the [Enter] key and then type what you want to say!"),
+ l("If you want to say something to a specific player, you can type \"/query Playername\" or \"/whisper Playername message\", this will create a new tab on your chat window.");
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book;
+ close;
+
+OnUse:
+ if (openbook())
+ read_book;
+ close;
+
+OnInit:
+ .book_name$ = "Communication Theory";
+ .distance = 1;
+ end;
+}
diff --git a/npc/001-2-5/mapflags.txt b/npc/001-2-5/mapflags.txt
new file mode 100644
index 00000000..973aa862
--- /dev/null
+++ b/npc/001-2-5/mapflags.txt
@@ -0,0 +1 @@
+001-2-5 mapflag town
diff --git a/npc/001-2-5/tutorial.txt b/npc/001-2-5/tutorial.txt
new file mode 100644
index 00000000..75835957
--- /dev/null
+++ b/npc/001-2-5/tutorial.txt
@@ -0,0 +1,266 @@
+// Evol/TMW2ML/TMWBR scripts.
+// Authors:
+// Ernando <ernando.quirino@hotmail.com>
+// Lunovox <rui.gravata@gmail.com>
+// Jesusalva <supremo@brasil.byethost22.com>
+// Toams
+// Objective: Complete Tutorial about Evol/Hercules mechanics
+// License: GPL v3
+
+001-2-5,34,32,0 script #EvolTutorial NPC_NO_SPRITE,{
+
+ function read_book {
+
+ setnpcdialogtitle l(.book_name$);
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("This book contains the knowledge collected by ukars about how the world works.");
+
+ @menu = 0; // reset for the rif
+
+ do
+ {
+ narrator S_NO_NPC_NAME,
+ l("Please select a chapter:");
+
+ mes "";
+
+ select
+ rif(@menu == 1, "► ") + l("Ch 1 — How to make money."),
+ rif(@menu == 2, "► ") + l("Ch 2 — Everything about monsters."),
+ rif(@menu == 3, "► ") + l("Ch 3 — Quests."),
+ rif(@menu == 4, "► ") + l("Ch 4 — Status."),
+ rif(@menu == 5, "► ") + l("Ch 5 — NPC's."),
+ rif(@menu == 6, "► ") + l("Ch 6 — Magic."),
+ rif(@menu == 7, "► ") + l("Ch 7 — Rules."),
+ rif(@menu == 8, "► ") + l("Ch 8 — Weather & Seasons."),
+ rif(@menu == 9, "► ") + l("Ch 9 — Experience."),
+ rif(@menu == 10, "► ") + l("Ch 10 — How I see my items?"),
+ rif(@menu == 11, "► ") + l("Ch 11 — How trade with other players?"),
+ rif(@menu == 12, "► ") + l("Ch 12 — How hunt monsters?"),
+ rif(@menu == 13, "► ") + l("Ch 13 — How talk with someone?"),
+ rif(@menu == 14, "► ") + l("Ch 14 — Change your appearing."),
+ rif(@menu == 15, "► ") + l("Ch 15 — Commands."),
+ rif(@menu == 16, "► ") + l("Ch 16 — Shortcuts.");
+
+ switch (@menu) {
+ case 1:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Merchants like to buy body parts of killed monsters and animals because they can make items and equipment."),
+ l("Some others also like to buy them to keep as trophies. Either way, you can make some money with that."),
+ l("You must find someone willing to buy, they usually will buy almost anything you have, even items which cannot be replaced, so be careful."),
+ l("You must \"add\" the items you plan on selling, and then press \"sell\" to confirm. You'll have this time to review."),
+ l("Some, but not all, from the rare or non-replaceable items will have a warning when you try to sell them."),
+ l("You can also make money %s. Nobody pays better than people in need of help.", b(l("by doing quests")));
+ break;
+ case 2:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Monsters are everywhere. They're a plague we're trying to get rid of."),
+ l("There are three types of monsters: the aggressive, the neutral, and the collaborative."),
+ l("Aggressors always know when they are in danger! Therefore, they are always on standby, attacking anyone who appears ahead."),
+ l("Neutral monsters do not have such a sense of danger."),
+ l("They will not attack anyone unless they are attacked first."),
+ l("Normally, collaborative monsters behave like neutral monsters. Unless someone of the same species is in danger, at which point they all take an aggressive stance against the aggressor."),
+ l("It's always good to see if you have a lot of them around before you think about attacking one!"),
+ l("Also, most monsters get enraged and will attack whoever is closest to them, regardless of anything else."),
+ l("Not all monsters will do this, but most will. So if you see a monster running after a player and you stand in the way..."),
+ l("...It'll most likely attack you, instead."),
+ l("One last thing to keep in mind... If you are surrounded, you'll suffer an agility and defense penalty."),
+ l("But if you and other players surrounds the monster instead, they'll suffer the same penalties!"),
+ l("Any boss which was previously unhittable, can be hit with appropriate number of attackers.");
+ break;
+ case 3:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("There are people in the world who need help!"),
+ l("Most of these people will not think twice before giving a nice reward to anyone who helps them."),
+ l("So be nice and help people along the way!"),
+ l("Usually, they'll have an exclamation mark over their heads. But some quests are hidden, so talk to people and have fun!");
+ break;
+ case 4:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("People vary greatly in the amount of strength, agility, dexterity, intelligence, vitality and luck."),
+ l("%s helps you carry more items and also gives you a more forceful blow, but ends up not being very interesting if you focus on weapons that use projectiles, such as the bow.", b(l("Strength"))),
+ l("Greater %s allows you to attack faster and has a greater chance of evading attacks.", b(l("agility"))),
+ l("Your %s determines your ability to hit monsters and is valuable to players who prefer weapons that use projectiles.", b(l("dexterity"))),
+ l("%s determines how many blows you can take before you die. It also affects status effects, like poison.", b(l("Vitality"))),
+ l("%s is very useful for alchemy and magic, but nowadays there are few opportunities to use it.", b(l("Intelligence"))),
+ l("Your %s determines several small things, including critical attacks, but DOES NOT affect drop rates.", b(l("luck"))),
+ l("A critical hit deals added damage and disregards defense. A critical always hit, although it can be blocked just fine."),
+ l("On a side note, more defense is always good, but the damage won't decrease on the same rate that defense raises."),
+ l("Also note that if you are in overweight, your natural regen will halt. 90% in weight, and you won't be able to attack."),
+ l("I recommend that you train your agility a great deal, since most monsters out there aren't really amazing at hitting you."),
+ l("For now do not take too much time to work on your intelligence, after all, magic use is very restricted nowadays."),
+ l("You can allocate point on those attributes every time you level up."),l("There's also a job level, which produces green sparkles when you level it."),
+ l("Job Level and certain equips can affect your status. You'll see the modifiers with a + sign."),
+ l("Do note that Job Level gives you skill points, and the status bonuses are really minor.");
+ break;
+ case 5:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("NPC's or non-playable characters are characters that are always in the game, offering a wide variety of reactions, from a simple friendly conversation to a desperate request for help."),
+ l("%s People usually doesn't shout, they talk. Because this, if you are too far, an NPC won't hear you.",b(l("IMPORTANT:"))),
+ l("When this is the case, you should get closer to the NPC, until they hear you."), l("If you are above the NPC and they still doesn't hear you, this mean they are deaf - you should report this!");
+ break;
+ case 6:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Magic was banned for lore reasons? Seriously, after the mana war, only small tricks are allowed."),
+ l("It was heard about some adventurers whom obtained and use advanced magic, but that is still seen with bad eyes.");
+ break;
+ case 7:
+ mes "";
+ callfunc "GameRules";
+ break;
+ case 8:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ /*
+ // TODO: Implement Day/Night Cycle
+ mes l("First of, there's a day/night cycle on the game.");
+ if (is_night())
+ mes l("It's currently night, that's why Candor is dark.");
+ else
+ mes l("It's currently day, but when night falls, Candor will become darker.");
+ next;
+ mes l("During night, the monsters usually respawn faster. That can be a problem with aggressive monsters.");
+ mes l("I also hear fisherman likes to fish at night. They say the catch is bigger, if you understand me.");
+ next;
+ */
+ /*
+ // TODO: Implement Weather Cycle
+ mes l("There's also weather, meaning it can rain, snow, or even happen a sandstorm. They are usually cosmetic, but...");
+ mes l("...who knows if there isn't a secret in that?");
+ next;
+ */
+ /*
+ // TODO: Implement Season Cycle
+ mes l("Besides this, there is Seasons. You know, summer, autumn, winter and spring.");
+ mes l("Each season unlocks a set of quests and drops which can only be obtained on the season.");
+ next;
+ mes l("Think on Season Quests as a yearly quest which you have three months to do.");
+ mes l("We follow north hemisphere seasons in case you're wondering.");
+ next;
+ */
+ // We commented everything so we need something here
+ l("There is no day/night, weather, or season cycle in TMW yet.");
+ break;
+ case 9:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Experience can be gained by completing quests and killing monsters. When you accumulate enough experience, you'll level up!"),
+ l("Each level up will buff your base stats, and give you stats points to allocate."),
+ l("There's also a job level, which produces green sparkles when you level it."),
+ l("Job Level and certain equips can affect your status. You'll see the modifiers with a + sign.");
+ /*
+ // TODO: Evol doesn't have experience per mob level adjustment yet, nor have @monsterinfo for all players
+ mes l("Also, you'll get more experience by killing monsters stronger than you, and less experience by killing monsters weaker than you.");
+ mes l("You can find out the monster strength by using \"@monsterinfo <English Monster Name>\". Check the level in it!");
+ next;
+ */
+ break;
+ case 10:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You can see all your equipment by pressing the F3 key."),
+ l("To equip or unequip an item, select it and press the 'Equip' or 'Unequip' button. You can not 'Equip' or 'Unequip' when talking to someone."),
+ l("Dress up! Do not walk without clothes! Always wear your items! They leave you less vulnerable to attacks and stronger to defeat your opponents."),
+ /*
+ // TODO: Evol doesn't have equipment set bonuses yet
+ mes b(l("Remember that some equipment sets will give you hidden stat bonuses! So dress yourself in a fashion way, if possible!"));
+ next;
+ */
+ l("To discard an item you no longer want, select it and press the 'Discard' button. Generic items can be discarded or sold."),
+ l("Some special items cannot be traded, discarded, nor sold. With a right click, you can also protect normal items as if they were special ones."),
+ l("There are three types of items."),
+ l("Those for consumption, equipment and generics."),
+ l("Items for consumption, like potions, can only be used once."),
+ l("Once used, they will disappear from your inventory."),
+ l("Equippable items are armour, weapons and accessories."),
+ l("They can be equipped to make your look more interesting or to improve some of its features."),
+ l("Generic items are used for different purposes. In creating other items, to swap and sell, to collect, etc.");
+ break;
+ case 11:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Press the '###keyTrade;' key to ignore or accept business proposals. You and the other citizen who want to negotiate need to be in the configuration that accepts negotiations. if your configuration is 'Ignoring business proposals', then you will not receive the warning from any citizen wanting to negotiate with you, and you will not be able to initiate negotiations."),
+ l("To negotiate with other citizens, you should click the second mouse button on some other citizen who is accepting negotiations, and select the 'Negotiation' option from the menu that will appear."),
+ l("After you have confirmed the negotiation, a window with a vertical split will appear. The left side are the items you intend to offer in trading. The right side are the items that the other citizen intends to offer in trading."),
+ l("Open your inventory window (###keyWindowInventory; key) next to the trading window. Select an item you want to offer, and then press the Add button. To add money to the negotiation, enter the amount you will offer and press the Change button."),
+ l("When you have added all the items and money you want, press the 'Propose Trade' button. The other citizen must also press the 'Propose Trade' button."),
+ l("If the proposal is not convenient for you, just close the trading window to cancel the exchange of items and money. But if both press the 'Accept Negotiation' button, then the marketing will be finished."),
+ l("Remember! You're trading things, not lending/borrowing them. You are solely responsible for everything you own.");
+ break;
+ case 12:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Note down. To hunt a target you must click the primary mouse button on it. Avoid fighting monsters or citizens much stronger than you. %s", b(l("You will lose experience if you are defeated."))),
+ l("Within the cities is a place safe enough not to be attacked by another person (except during wars). But outside of them there are some places where the citizen can be attacked by enemies from other realms, or even by someone from the same realm."),
+ l("There are some stones scattered around the world that mark your point of return in case of defeats. Some ship chests may also serve as a return point. You can also select some beds in case of defeats."),
+ l("Almost all creatures drop useful items when defeated. To get the dropped item press the '###keyPickup;' key next to the item or click the primary button on the item."),
+ l("To focus on a creature, press the '###keyTargetMonster;' key. To focus on another citizen, press the '###keyTargetPlayer;' key. To attack the focused target press the '###keyAttack;' key or click the primary button on the creature."),
+ l("To focus on an NPC, press the '###keyTargetNPC;' key. To talk to him press the '###keyTalk;' key."),
+ l("To defocus or stop attacking, press Shift + A."),
+ l("You can, however, use '###keyTargetAttack;' to auto-select a monster and attack them. This usually also collects drops, but press '###keyPickup;' to be sure.");
+ break;
+ case 13:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("To display the dialog box with other citizens, press the '###keyWindowChat;' key."),
+ l("To speak in public select the 'General' tab. It serves to talk to people who are appearing on your screen."),
+ l("To speak privately with someone, click the second mouse button on the citizen and select the 'Whisper' option."),
+ l("In order to enter a message press the '###keyChat;' key, this will display the white box of typing. Type your message there and press '###keyChat;' again to send your speech."),
+ l("To speak privately to a friend who is not appearing on your screen, type the command '%s' and press '###keyChat;'. This command will open a long-distance dialog that has the name of who you want to talk to. Select this new tab and send your message through it.",b(l("/q [Player Name] "))),
+ l("And by last, to speak to everyone online, besides whoever might be idling on IRC, select the '#irc' tab."),
+ l("But be careful: do not scream by using a lot of capital letters, do not repeat yourself over and over, and above all DO NOT SPAM, or you may be severely penalized.");
+ break;
+ case 14:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("NPC stylists will cut your hair!"),
+ l("They are known to use a revolutionary hair growth formula."),
+ l("You will be amased by all the colors of hair dye they have.");
+ break;
+ case 15:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You can execute commands by typing them in the chat window. They start with a '/' or '@' followed by the name of the command."),
+ l("%s clears the text box.", b("/clear")),
+ l("%s %s allows you to send a private message to the player. if [name] contains spaces, it must be enclosed in quotation marks.", b("/whisper"),l("[name]")),
+ l("%s displays amount of currently connected players.", b("/who")),
+ l("%s shows the number of people in the neighbourhood.", b("/present")),
+ l("%s shows the name of the map you are in.", b("/where")),
+ l("%s explains how to use all client commands.", b("/help")),
+ l("%s lists even more advanced commands, but some of them can only be used by admins or GM's.", b("@commands")),
+ l("%s will help when the client starts lagging. If you see an attack but no monsters, that's the cause.", b("@resync")),
+ l("%s allows you to change game language, anytime, anywhere.", b("@lang")),
+ l("%s will tell you all the rules once again.", b("@rules")),
+ //mes l("@toevent will warp you to event island, if an event is happening, of course.");
+ //mes l("@discord allows you to setup Discord integration settings.");
+ //mes l("@ucp allows you to manage your account, eg. recover lost email.");
+ //next;
+ //mes l("@resyncall is the more powerful version of @resync. It'll reload everything, even the clouds if needed.");
+ l("%s and %s will show this informative and absurdely big tutorial book." ,b("@info"),b("@tutorial"));
+ break;
+ case 16:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("There are many key combinations, press F1 to see a short list of them!");
+ break;
+ }
+
+ } while (true);
+ end;
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnRemoteHelp:
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "Hitchiker's Guide To The Mana World";
+
+ bindatcmd "info", "#EvolTutorial::OnUse", 0, 0, 0;
+ bindatcmd "tutorial", "#EvolTutorial::OnUse", 0, 0, 0;
+
+ .distance = 1;
+ end;
+}
diff --git a/npc/001-2-6/_import.txt b/npc/001-2-6/_import.txt
new file mode 100644
index 00000000..cc06496d
--- /dev/null
+++ b/npc/001-2-6/_import.txt
@@ -0,0 +1,8 @@
+// Map 001-2-6: First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-6/_warps.txt",
+"npc/001-2-6/books.txt",
+"npc/001-2-6/christopher.txt",
+"npc/001-2-6/dolfina.txt",
+"npc/001-2-6/leonard.txt",
+"npc/001-2-6/mapflags.txt",
diff --git a/npc/001-2-6/_warps.txt b/npc/001-2-6/_warps.txt
new file mode 100644
index 00000000..e778bf33
--- /dev/null
+++ b/npc/001-2-6/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-6: First Floor warps
+001-2-6,57,38,0 warp #001-2-6_57_38 3,0,001-2-4,57,28
diff --git a/npc/001-2-6/books.txt b/npc/001-2-6/books.txt
new file mode 100644
index 00000000..8e6f4997
--- /dev/null
+++ b/npc/001-2-6/books.txt
@@ -0,0 +1,345 @@
+// Evol scripts.
+// Authors:
+// gumi
+// Jesusalva
+// Reid
+// WildX
+// Description:
+// Aemil books
+
+001-2-6,39,41,0 script #001-2-6-Book1 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("Master Piou sat on a tree,"),
+ l("Holding a cheese in his beak."),
+ l("Master Fluffy was attracted by the odour,"),
+ l("And tried to attract him thus."),
+
+ l("\"Mister Piou, good day to you."),
+ l("You are a handsome and good looking bird!"),
+ l("In truth, if your song is as beautiful as your plumage,"),
+ l("You are the Phoenix of this forest.\""),
+
+ l("Hearing these words the Piou felt great joy,"),
+ l("And to demonstrate his beautiful voice,"),
+ l("He opened his mouth wide and let drop his prey."),
+ l("The Fluffy seized it and said:"),
+
+ l("\"My good Sir,"),
+ l("Know that every flatterer,"),
+ l("Lives at the expense of those who take him seriously:"),
+ l("This is a lesson that is worth a cheese no doubt.\""),
+
+ l("The Piou, embarrassed and confused,"),
+ l("Swore, though somewhat later, that he would never be "),
+ l("tricked thus again."),
+
+ "-- " + l("Aesop"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "The Piou and The Fluffy";
+ .distance = 1;
+ end;
+}
+
+001-2-6,48,41,0 script #001-2-6-Book2 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("Poem is making the words dance"),
+ l("Words become music and glance"),
+ l("Over lovers under a starry night"),
+ l("Whose eyes listen under Moonlight"),
+
+ l("No matter the grammar"),
+ l("If words beat in rhythm"),
+ l("Find an order with them"),
+ l("As on anvil strikes the hammer"),
+
+ l("No matter the spelling"),
+ l("Just say something sparkling"),
+ l("If not, how could CrazyKatiektch"),
+ l("Say her love to glamourous Gliktch?"),
+
+ l("True be or not true be"),
+ l("That's not the question"),
+ l("And rhyming is not too"),
+ l("If you don't like to"),
+ l("Share your mind is your mission"),
+ l("Whatever inside can be"),
+
+ l("Don't be shy, you are nice"),
+ l("From your mind, break the ice"),
+ l("Whatever your idea"),
+ l("It's the good one and, ahem!"),
+ l("That makes everybody"),
+ l("Able to write a poem"),
+
+ "-- " + l("Nard"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "Poem about Poems";
+ .distance = 1;
+ end;
+}
+
+001-2-6,43,39,0 script #001-2-6-Book3 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("Hush now and hear the chorus of the woods"),
+ l("Bent trees whistling with the beat of the drum"),
+ l("With no choir master nor voice to be sung"),
+ l("The music of the trees floats through the breeze"),
+ l("Sleep well my angel but don't follow along"),
+ l("Because the voices of death sing a sweet song"),
+
+ "-- " + l("Princess Slayer"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "Chorus of the Woods";
+ .distance = 1;
+ end;
+}
+
+001-2-6,54,28,0 script #001-2-6-Book4 NPC_NO_SPRITE,{
+
+ function read_book {
+ narrator(S_FIRST_BLANK_LINE,
+ l("Aemil was once a magnificent land unknown to us all."),
+ l("Before the end of the Mana War, a band of adventurers formed in the Ancean region of Argaes from those who had lost their homes and families."),
+ l("They sailed from Hurnscald to Tulimshar and then Nivalis, the last permanent settlements of talpans."),
+ l("There, they gathered merchants and warriors to join them in a journey to find a new land on which to live."),
+ l("The group found the support of Tulimshar's merchant lords and was given ships to sail east."),
+ l("They sailed past the Clear Sea and towards the Long Ocean which nobody had explored before."),
+ l("The newly created Fleet of Ancea travelled so far that they were never heard from again."),
+ l("Their leaders then came to the conclusion that an alliance was the only way they could survive."),
+ l("They eventually found a new land after much hardship and named it Aurora, after its beautiful sunrise."),
+ l("A great city, eventually to become larger than the cities of Ancea, rose on the coast of Aemil. This city was named Esperia."),
+ l("However..."),
+ l("The end of the story got erased, probably because of the sea water. Some pages are still missing. Thus much is lost to time, including the author's name."));
+ }
+
+OnUse:
+ if (openoldbook())
+ read_book();
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+
+001-2-6,57,41,0 script #001-2-6-Book5 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("So you have now a pet, who is loyal to you. It'll follow you everywhere, but there are two things you must know."),
+ l("Do not let intimacy and hunger get to zero. If any of those get to zero, it'll leave you forever."),
+ l("Pious must keep a strict diet composed of Piberries."),
+ l("However, you should only give food when it's hungry, otherwise it'll believe you're a bad owner and intimacy will decrease."),
+ l("To perform most actions, like feeding and renaming, just right-click it. You can even put it back on the egg if its following gets too annoying."),
+ l("Give your pet a nice name, and keep it healthy, and you'll be a successful pet owner!"),
+ l("When you intimacy is high, it'll increase your stats and who knows, might even help you in combat!"),
+ l("...And if you're still trying to check your pet stats, just hover it with your mouse. Thanks."),
+
+ "-- " + l("Animals Protection Agency of Aemil"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "Fluffy Animals who Love Their Owners";
+ .distance = 1;
+ end;
+}
+
+001-2-6,44,44,0 script #001-2-6-Book6 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("World Story For Dummies, Vol I - Ancean Era: From Keshlam to an Empire"),
+ l("The collection of four books entitled “World Story For Dummies” is based on the uncessable work from the Ukar scholars, thanks to whom this wouldn't be possible."),
+ l("The “Ancean Era” is a term used to defined the time period between the beginning of recorded history and the events at the Mana Tree, and thanks to Ukar scholars, this is widely accepted as year 1 on all Gasaron."),
+ l("The first talpan settlement to develop an advanced political structure and to become a city-state was Keshlam."),
+ l("Keshlam expanded rapidly under the rule of King Janeb the Founder, and soon annexed the whole Ancea continent - excluding solely the Land Of Fire - to its domains, creating the Platinum Kingdom."),
+ l("Three cities developed on the eastern side of Ancea: Tulimshar, Hurnscald and Nivalis."),
+ l("The Platinum Kingdom grew and prospered, and drew most of the talpan population to the safety of the walls of Keshlam, Tulimshar, Hurnscald and Nivalis."),
+
+ l("-- Continues on Volume II --"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "World Story For Dummies, Vol I";
+ .distance = 1;
+ end;
+}
+
+001-2-6,53,44,0 script #001-2-6-Book7 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("World Story For Dummies, Vol II - Ancean Era: Revolutions and Independence"),
+ l("On the year 206CCE, after a long crisis of succession, a minor noble only known as Queen Platyna the Red came to inherit the Platinum Crown."),
+ l("Due to neglect with day-to-day administration, which she delegated to her council, and uncontrolled expenses, the kingdom faced its first economic crisis."),
+ l("With the growth of the Kingdom halted, slow maintenance, and two great famines which killed over half the talpan population, the council decided to seize power and depose Platyna the Red."),
+ l("On March 213CCE, Chancellor Benjamin Frost, with support of the council, proclaimed the Republic of Ancea. This event would become known as the Blue Revolution."),
+ l("Frost held the title of Lord Prince of the Republic for eighteen months, when the council deposed him and declared itself head of the state."),
+ l("The Republic of Ancea ceased to exist officially in August 216CCE, when the cities of Tulimshar, Hurnscald and Nivalis installed their own independent governments."),
+ l("The council, however, neglected day-to-day administration duties, and focused their efforts in regaining control of the rest of Ancea."),
+ l("This led Keshlam into rapid decline and its citizen began to emigrate to the other Cities. By the end of the Ancean Era, Keshlam City was a quarter of the original size."),
+
+ l("-- Continues on Volume III --"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "World Story For Dummies, Vol II";
+ .distance = 1;
+ end;
+}
+
+001-2-6,44,47,0 script #001-2-6-Book8 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("World Story For Dummies, Vol III - Aemilean Era: The Mana Tree and The Mana War"),
+ l("Aemilean Era. Tulimshar, Hurnscald and Nivalis held power of their surrounding lands, except for the Land Of Fire and Keshlam City."),
+ l("All races were in peace until the talpans set forth to discover the Source of Magic, based on Ukar scholars studies."),
+ l("Free Mana travels in many directions, and this search took several years before the expedition finally found the right direction to follow."),
+ l("A large tree was found in a deep cave underneath the island of Candor. Despise the darkness of the cave and absence of leaves, the tree grew strong. It gave light off itself and its energy empowered the wizards."),
+ l("The tree was entitled The Mana Tree, and the Wizard Order took control over Candor Island. They learnt to control the mana flow, and limited its use, claiming Magic to be too dangerous for public use."),
+ l("This action was met with widespread opposition from all races, and a war broke. The tritans led the offensive, in attempts to keep the tree untouched and mana available for all."),
+ l("Unable to win, the tritans attacked Hurnscald. While talpan troops moved in attempts to avoid its fall, the Kralog and Ukar joined the tritans and they took the city."),
+ l("The next and final battle happened at Candor. Wizards attacks from both sides near the Mana Tree provoked a Mana Storm. A Great Quake shook the earth of Ancea and the land began to split. Geography changed, and Keshlan vanished from the map."),
+ l("The Mana Tree was lost, the caves entrances destroyed, and the Wizard Order was split in two: One part was on Candor, and other at the Magic Tower."),
+ l("After this war, the Raijin race was born. A race born of Magic. Talpans encapsulated in a Mana storm and altered forever."),
+
+ l("-- Continues on Volume IV --"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "World Story For Dummies, Vol III";
+ .distance = 1;
+ end;
+}
+
+001-2-6,53,47,0 script #001-2-6-Book9 NPC_NO_SPRITE,{
+
+ function read_book {
+ setnpcdialogtitle(l(.book_name$));
+
+ narrator(S_FIRST_BLANK_LINE | S_NO_NPC_NAME,
+ l("World Story For Dummies, Vol IV - Aemilean Era: The Fleet of Ancea"),
+ l("After the Mana War, the Ancea continent was mostly destroyed. It would take years to nature start repairing the damage of the event."),
+ l("A band of adventurers formed in Argaes from those who had lost their homes and families. They visited the three permanent talpan settlements: Tulimshar, Hurnscald and Nivalis."),
+ l("They gathered merchants and warriors to join them in a journey to find new lands to live in. Tulimshar's merchant lords gave them ships to sail east."),
+ l("The newly created Fleet of Ancea travelled so far that they were never heard from again. They found a continent, present on legends of explorers who never came back."),
+ l("They named this continent as Aemil, in honour of one of such explorers. The area they docked in was called Aurora, after its beautiful sunrise."),
+ l("The first village build was named Esperia. Aurora region was very fertile, and for this reason they moved towards countryside and built farms."),
+ l("In hopes of one day reconnect with the people of Ancea and establish a trade between the two continents, The City of Artis was founded. The Aemil Continent has then grown without contact with the people of Ancea."),
+
+ "-- " + l("The Ukar Historical Association on Aemil"));
+ }
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book();
+ close;
+
+OnUse:
+ if (openbook())
+ read_book();
+ close;
+
+OnInit:
+ .book_name$ = "World Story For Dummies, Vol IV";
+ .distance = 1;
+ end;
+}
+
diff --git a/npc/001-2-6/christopher.txt b/npc/001-2-6/christopher.txt
new file mode 100644
index 00000000..6ad237e5
--- /dev/null
+++ b/npc/001-2-6/christopher.txt
@@ -0,0 +1,68 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Librarian
+
+001-2-6,57,46,0 script Christopher NPC_CHRISTOPHER,{
+ function ghost_in_the_library
+ {
+ narrator S_LAST_NEXT,
+ l("Christopher is surrounded by the sunlight from the window.");
+
+ speech
+ l("To be a legend, you've either got to be dead or excessively old!"),
+ l("I think that I am now both..."),
+ l("I mean, I am very tired to move all of these books!");
+
+ return;
+ }
+
+ function need_help
+ {
+ speech S_LAST_NEXT,
+ l("Do you need help with something?");
+
+ switch (select(l("What kinds of books are there here?"),
+ l("You seem a bit tired sir."),
+ l("Nothing.")))
+ {
+ case 1:
+ npctalk3 l("You can find novels and poems on this floor.");
+ break;
+ case 2:
+ mes "";
+ ghost_in_the_library();
+ break;
+ case 3:
+ npctalk3 l("I love peace and quiet, that's a good choice.");
+ }
+ return;
+ }
+
+ function not_so_loud
+ {
+ npctalkonce l("This floor is reserved for quiet reading, don't speak too loud.");
+
+ return;
+ }
+
+ switch (rand(3))
+ {
+ case 0:
+ ghost_in_the_library();
+ break;
+ case 1:
+ need_help();
+ break;
+ case 2:
+ not_so_loud();
+ break;
+ }
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-6/dolfina.txt b/npc/001-2-6/dolfina.txt
new file mode 100644
index 00000000..d5cc1610
--- /dev/null
+++ b/npc/001-2-6/dolfina.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Aemil
+
+001-2-6,31,44,0 script Dolfina NPC_ELVEN_FEMALE_READING,{
+ mesn;
+ mesq l("Stop disturbing me, I already re-read that part twice because of you!");
+
+ goto L_Close;
+
+L_Close:
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
diff --git a/npc/001-2-6/leonard.txt b/npc/001-2-6/leonard.txt
new file mode 100644
index 00000000..9d0346c1
--- /dev/null
+++ b/npc/001-2-6/leonard.txt
@@ -0,0 +1,88 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Librarian
+
+001-2-6,52,28,0 script Leonard NPC_LEONARD,{
+
+ function esperia_city
+ {
+ speech S_FIRST_BLANK_LINE,
+ l("You have put your finger on it, I am not."),
+ l("I grew up and lived a good while in Esperia, the capital city."),
+ l("This place is surrounded by two very important elements: academia and the arts. I was surrounded by theater, music, dance, museums..."),
+ l("I had a great childhood in Esperia!"),
+ l("It was wonderful.");
+
+ emotion E_HAPPY;
+
+ return;
+ }
+
+ function need_help
+ {
+ speech S_LAST_NEXT,
+ l("Do you need help with something?");
+
+ switch (select(l("What kinds of books are there here?"),
+ l("Are you a native from Artis?"),
+ l("Nothing.")))
+ {
+ case 1:
+ closeclientdialog;
+ npctalk3 l("You can find novels and poems on this floor.");
+ break;
+ case 2:
+ esperia_city();
+ break;
+ case 3:
+ closeclientdialog;
+ npctalk3 l("Good day to you!");
+ }
+ return;
+ }
+
+ function not_so_loud
+ {
+ npctalkonce l("This floor is reserved for quiet reading, don't speak too loud.");
+
+ return;
+ }
+
+ function miracle
+ {
+ npctalkonce l("The miracle is this: the more we share, the more we have.");
+
+ return;
+ }
+
+ function logic_wisdom
+ {
+ npctalkonce l("Logic is the beginning of wisdom, not the end.");
+
+ return;
+ }
+
+ switch (rand(4))
+ {
+ case 0:
+ logic_wisdom();
+ break;
+ case 1:
+ miracle();
+ break;
+ case 2:
+ not_so_loud();
+ break;
+ case 3:
+ need_help();
+ break;
+ }
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/001-2-6/mapflags.txt b/npc/001-2-6/mapflags.txt
new file mode 100644
index 00000000..f5ba3e95
--- /dev/null
+++ b/npc/001-2-6/mapflags.txt
@@ -0,0 +1 @@
+001-2-6 mapflag town
diff --git a/npc/001-2-7/_import.txt b/npc/001-2-7/_import.txt
new file mode 100644
index 00000000..6d588bf8
--- /dev/null
+++ b/npc/001-2-7/_import.txt
@@ -0,0 +1,4 @@
+// Map 001-2-7: City Hall
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-7/_warps.txt",
+"npc/001-2-7/mapflags.txt",
diff --git a/npc/001-2-7/_warps.txt b/npc/001-2-7/_warps.txt
new file mode 100644
index 00000000..d59fa937
--- /dev/null
+++ b/npc/001-2-7/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-7: City Hall warps
+001-2-7,36,46,0 warp #001-2-7_36_46 0,0,001-1,89,66
+001-2-7,46,31,0 warp #001-2-7_46_31 0,0,001-2-9,25,41
+001-2-7,26,31,0 warp #001-2-7_26_31 0,0,001-2-8,45,41
diff --git a/npc/001-2-7/mapflags.txt b/npc/001-2-7/mapflags.txt
new file mode 100644
index 00000000..69598b89
--- /dev/null
+++ b/npc/001-2-7/mapflags.txt
@@ -0,0 +1 @@
+001-2-7 mapflag town
diff --git a/npc/001-2-8/_import.txt b/npc/001-2-8/_import.txt
new file mode 100644
index 00000000..17bbd2dc
--- /dev/null
+++ b/npc/001-2-8/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-8: Left Wing
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-8/_warps.txt",
+"npc/001-2-8/doors.txt",
+"npc/001-2-8/mapflags.txt",
diff --git a/npc/001-2-8/_warps.txt b/npc/001-2-8/_warps.txt
new file mode 100644
index 00000000..43412f72
--- /dev/null
+++ b/npc/001-2-8/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-8: Left Wing warps
+001-2-8,46,41,0 warp #001-2-8_46_41 0,0,001-2-7,27,31
diff --git a/npc/001-2-8/doors.txt b/npc/001-2-8/doors.txt
new file mode 100644
index 00000000..7b34c4da
--- /dev/null
+++ b/npc/001-2-8/doors.txt
@@ -0,0 +1,59 @@
+// Evol scripts.
+// Author:
+// Jesusalva
+// Description:
+// The Door for Town Archives
+
+001-2-8,38,30,0 script #ArtisArchiveGate NPC_NO_SPRITE,0,0,{
+ function breakIn;
+ function notToday;
+
+ .@q=getq(ThiefQuests_Artis);
+ mes l("The door is locked and you don't have the key.");
+ next;
+ mes l("This is probably where the town files are kept.");
+ if (.@q > 1) notToday();
+ if (.@q == 1) breakIn();
+ close;
+
+function notToday {
+ mesc l("I have nothing else to do down there.");
+ return;
+}
+
+function breakIn {
+ mesc l("Should we break in? We'll be in a bad situation if we're found out.");
+ next;
+ // Better to not use only a pine!
+ if (LockPicking(2, 3, false)) {
+ // Delete previous timers.
+ deltimer("#ArtisThiefBook_0::OnBust1");
+ deltimer("#ArtisThiefBook_0::OnBust2");
+ deltimer("#ArtisThiefBook_0::OnBust3");
+ deltimer("#ArtisThiefBook_0::OnBust4");
+ // Begin the catch timer (addtimer)
+ addtimer 30000, "#ArtisThiefBook_0::OnBust1";
+ warp "001-2-43", 27, 34;
+ } else {
+ if (ArrestedChances()) {
+ mesc l("Arrested!");
+ mesc l("You'll now spend a few minutes on the jail to reflect on your actions.");
+ ArrestPlayer(5);
+ } else {
+ mesc l("You're almost found out, but manage to make a quick escape!");
+ warp "001-1", 90, 55;
+ }
+
+ }
+ return;
+}
+
+OnTouch:
+ npctalkonce l("Dang! It is locked.");
+ end;
+
+OnInit:
+ .distance=1;
+ end;
+}
+
diff --git a/npc/001-2-8/mapflags.txt b/npc/001-2-8/mapflags.txt
new file mode 100644
index 00000000..3def9ed2
--- /dev/null
+++ b/npc/001-2-8/mapflags.txt
@@ -0,0 +1 @@
+001-2-8 mapflag town
diff --git a/npc/001-2-9/_import.txt b/npc/001-2-9/_import.txt
new file mode 100644
index 00000000..ebac336c
--- /dev/null
+++ b/npc/001-2-9/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-2-9: Right Wing
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-2-9/_warps.txt",
+"npc/001-2-9/janus.txt",
+"npc/001-2-9/mapflags.txt",
diff --git a/npc/001-2-9/_warps.txt b/npc/001-2-9/_warps.txt
new file mode 100644
index 00000000..b4d3c594
--- /dev/null
+++ b/npc/001-2-9/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-2-9: Right Wing warps
+001-2-9,24,41,0 warp #001-2-9_24_41 0,0,001-2-7,45,31
diff --git a/npc/001-2-9/janus.txt b/npc/001-2-9/janus.txt
new file mode 100644
index 00000000..200dbd6c
--- /dev/null
+++ b/npc/001-2-9/janus.txt
@@ -0,0 +1,170 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Party NPC
+// Variable:
+// General_Janus
+// Values:
+// 0 Default.
+// 1 Basic information given.
+// 2 Party creation enabled.
+// 3 Guild certificate given.
+
+001-2-9,30,28,0 script Janus NPC_JANUS,{
+
+ function create_party {
+ .@party_price = 1000;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Creating a party has some advantages, it's a pretty good choice!"),
+ l("I remember when I created my first party, we were amazed to share some experience with a small group of adventurer..."),
+ l("Oh! And our party chat was really entertaining, I do highly recommend you to share this fun as well."),
+ l("The cost to create a party is @@ E, are you interested?",
+ "The cost to create a party is @@ E, are you interested?", .@party_price);
+
+ if (askyesno() == 1)
+ {
+ if (Zeny < .@party_price)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("You don't have enough money, bring @@ E.", .@party_price);
+ }
+ else
+ {
+ Zeny -= .@party_price;
+ setq General_Janus, 2;
+ skill NV_BASIC, 7, 0;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("Awesome, come back if you ever want to create a larger group!");
+ }
+ }
+ }
+
+ function create_guild {
+ .@guild_price = 35000;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh oh... I see, your party became so big that you want to create an even larger structure?"),
+ l("Or do you want to keep your friendships and adventures in different groups?"),
+ l("Anyway, the guild creation is perfect for both!"),
+ l("You can keep your current party as it is, while leading or being part of a guild in order to talk and share different items with all of its members!"),
+ l("The @@ is a one time item, you can use it as many times as you want, but you can only have one!", getitemlink(GuildCertification)),
+ l("The cost to create a guild is @@ E, are you interested?",
+ "The cost to create a guild is @@ E, are you interested?", .@guild_price);
+
+ if (askyesno() == 1)
+ {
+ if (Zeny < .@guild_price)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("You don't have enough money, bring @@ E.", .@guild_price);
+ }
+ else
+ {
+ inventoryplace GuildCertification, 1;
+ Zeny -= .@guild_price;
+ setq General_Janus, 3;
+ getitem GuildCertification, 1;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("Enjoy the fraternity and excitement of your future guild!");
+ }
+ }
+ }
+
+ function explain_service {
+ // NOTE: "human" refers to all races in Gasaron, so usage is correct.
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You are on the human resource wing of the Town Hall."),
+ l("We offer party and guild certifications and we can also teach you how to use some basic communication skills."),
+ l("Do you know how to speak with people around you?");
+
+ if (askyesno() == 2)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You lack some very basic skills...");
+
+ if (compareandsetq(General_Janus, 0, 1))
+ {
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("This book contains everything you should know about it, take it!");
+
+ inventoryplace CommunicationTheory, 1;
+ getitem CommunicationTheory, 1;
+ }
+ else
+ {
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("You can read the book that I gave you earlier at the library if you lost it.");
+ }
+ }
+ else
+ {
+ if (compareandsetq(General_Janus, 0, 1))
+ {
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("Anyway."),
+ l("This book contains everything you should know about it, take it!");
+
+ inventoryplace CommunicationTheory, 1;
+ getitem CommunicationTheory, 1;
+ }
+
+ }
+
+ return;
+ }
+
+ function janus_is_not_ianus {
+ speech S_FIRST_BLANK_LINE,
+ l("Janus!");
+ emotion E_UPSET;
+ next;
+
+ speech S_LAST_NEXT | S_NO_NPC_NAME,
+ l("Ianus is from the Legion of Aemil, don't compare me to this brigand.");
+
+ return;
+ }
+
+ speech S_LAST_NEXT,
+ l("Welcome!");
+
+ do
+ {
+ // Beta users by-pass check.
+ if (getskilllv(NV_BASIC) > 6 && getq(General_Janus) == 1)
+ {
+ setq General_Janus, 2;
+ }
+
+ select
+ rif(getq(General_Janus) == 1, l("I would like to create a party.")),
+ rif(getq(General_Janus) == 2, l("I would like to create a guild.")),
+ l("What service do you offer?"),
+ l("Your name is Ianus or Janus?"),
+ menuaction(l("Quit"));
+
+ switch (@menu)
+ {
+ case 1:
+ create_party;
+ break;
+ case 2:
+ create_guild;
+ break;
+ case 3:
+ explain_service;
+ break;
+ case 4:
+ janus_is_not_ianus;
+ break;
+ }
+ } while (@menu != 5);
+
+ closeclientdialog;
+ goodbye;
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/001-2-9/mapflags.txt b/npc/001-2-9/mapflags.txt
new file mode 100644
index 00000000..47b7f630
--- /dev/null
+++ b/npc/001-2-9/mapflags.txt
@@ -0,0 +1 @@
+001-2-9 mapflag town
diff --git a/npc/001-3-0/_import.txt b/npc/001-3-0/_import.txt
new file mode 100644
index 00000000..502507be
--- /dev/null
+++ b/npc/001-3-0/_import.txt
@@ -0,0 +1,6 @@
+// Map 001-3-0: Sewer
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-3-0/_mobs.txt",
+"npc/001-3-0/_warps.txt",
+"npc/001-3-0/gates.txt",
+"npc/001-3-0/mundane.txt",
diff --git a/npc/001-3-0/_mobs.txt b/npc/001-3-0/_mobs.txt
new file mode 100644
index 00000000..49443d5a
--- /dev/null
+++ b/npc/001-3-0/_mobs.txt
@@ -0,0 +1,39 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-3-0: Sewer mobs
+001-3-0,175,32,2,2 monster Ratto 1005,2,60000,30000
+001-3-0,201,54,2,2 monster Ratto 1005,3,25000,10000
+001-3-0,151,97,18,1 monster Ratto 1005,3,40000,15000
+001-3-0,101,111,8,3 monster Ratto 1005,4,30000,15000
+001-3-0,145,68,2,2 monster Ratto 1005,2,60000,30000
+001-3-0,146,28,2,1 monster Ratto 1005,2,60000,30000
+001-3-0,89,66,2,4 monster Ratto 1005,3,35000,15000
+001-3-0,56,50,8,4 monster Ratto 1005,4,35000,15000
+001-3-0,42,102,3,3 monster Ratto 1005,3,40000,20000
+001-3-0,157,80,2,2 monster Green Slime 1024,3,15000,80000
+001-3-0,190,58,3,19 monster Cave Maggot 1027,7,5000,15000
+001-3-0,172,46,1,2 monster Cave Maggot 1027,3,5000,15000
+001-3-0,175,50,0,4 monster Ratto 1005,2,60000,30000
+001-3-0,175,64,3,2 monster Cave Maggot 1027,4,5000,15000
+001-3-0,104,75,48,43 monster Cave Maggot 1027,25,500,2000
+001-3-0,90,68,1,6 monster Cave Maggot 1027,3,500,2000
+001-3-0,128,86,3,5 monster Green Slime 1024,3,500,2000
+001-3-0,42,103,3,5 monster Green Slime 1024,3,500,2000
+001-3-0,120,85,7,2 monster Little Green Slime 1025,2,500,2000
+001-3-0,147,122,3,5 monster Green Slime 1024,2,500,2000
+001-3-0,147,122,3,5 monster Green Slime 1024,2,500,2000
+001-3-0,107,109,4,2 monster Green Slime 1024,3,500,2000
+001-3-0,139,32,10,4 monster Little Green Slime 1025,2,500,2000
+001-3-0,86,131,4,2 monster Little Green Slime 1025,3,500,2000
+001-3-0,175,31,4,2 monster Little Green Slime 1025,2,500,2000
+001-3-0,147,67,4,2 monster Little Green Slime 1025,2,500,2000
+001-3-0,55,50,5,3 monster Giant Maggot 1076,1,25000,20000,Henry#001-3-2::OnGiantMaggot
+001-3-0,117,60,5,0 monster Cave Maggot 1027,25,500,2000
+001-3-0,156,43,5,2 monster Crafty 1018,3,12000,20000
+001-3-0,178,76,5,1 monster Crafty 1018,3,12000,20000
+001-3-0,86,97,5,1 monster Crafty 1018,3,12000,20000
+001-3-0,86,48,5,1 monster Crafty 1018,3,12000,20000
+001-3-0,61,104,5,0 monster Tortuga 1004,1,35000,300000
+001-3-0,54,85,5,0 monster Tortuga 1004,1,35000,300000
+001-3-0,114,62,5,0 monster Tortuga 1004,1,35000,300000
+001-3-0,167,100,6,1 monster Tortuga 1004,1,35000,300000
+001-3-0,41,104,2,3 monster Giant Maggot 1076,1,15000,15000,Henry#001-3-2::OnGiantMaggot
diff --git a/npc/001-3-0/_warps.txt b/npc/001-3-0/_warps.txt
new file mode 100644
index 00000000..d192e4ef
--- /dev/null
+++ b/npc/001-3-0/_warps.txt
@@ -0,0 +1,8 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-3-0: Sewer warps
+001-3-0,196,35,0 warp #001-3-0_196_35 0,0,001-1,197,35
+001-3-0,172,41,0 warp #001-3-0_172_41 0,0,001-3-1,34,58
+001-3-0,162,40,0 warp #001-3-0_162_40 0,0,001-3-1,23,57
+001-3-0,198,60,0 warp #001-3-0_198_60 0,0,001-1,199,61
+001-3-0,152,55,0 warp #001-3-0_152_55 0,0,001-1,152,51
+001-3-0,85,130,0 warp #001-3-0_85_130 0,0,001-1,86,130
diff --git a/npc/001-3-0/gates.txt b/npc/001-3-0/gates.txt
new file mode 100644
index 00000000..e8accc96
--- /dev/null
+++ b/npc/001-3-0/gates.txt
@@ -0,0 +1,201 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// The Sewer Gates, and Wheels.
+
+001-3-0,90,62,0 script #ArtisThiefGate_1 NPC_SEWER_GATE,0,0,{
+ // Extract the quest ID from name (or fail trying)
+ explode(.@ni$, .name$, "_");
+ .@id=atoi(.@ni$[1]);
+
+ .@q=getq(ThiefQuests_Artis);
+ .@q2=getq2(ThiefQuests_Artis);
+
+ // Check what you can do with the gate
+ if (.@q != .@id) {
+ mes l("This gate is closed.");
+ mesc l("No need to go through here, so lets not bother with it now.");
+ } else if (.@q2 != 2) {
+ mes l("This gate is closed.");
+ mesc l("It seems that it can be open using the mechanism on the side.");
+ } else {
+ mes l("This gate is open.");
+ mesc l("I should still be careful to don't get caught.");
+ }
+ close;
+
+OnTouch:
+ updateSpotlight(true);
+ end;
+
+OnOpenSesame:
+ // Opening
+ if (!.busy) {
+ .dir=2;
+ .busy=true;
+ initnpctimer;
+ }
+ end;
+
+// Open
+OnTimer2200:
+ .dir=4;
+ end;
+
+// Closing
+OnTimer8000:
+ .dir=6;
+ end;
+
+// Closed
+OnTimer10400:
+ .dir=0;
+ end;
+
+// Don't reply immediately, wait a tiny bit
+OnTimer11000:
+ .busy = false;
+ stopnpctimer;
+
+OnInit:
+ .busy = false;
+ .distance = 1;
+ end;
+}
+
+
+
+001-3-0,92,61,0 script #ArtisThiefWheel_1 NPC_SEWER_WHEEL,{
+ // Extract the quest ID from name (or fail trying)
+ explode(.@ni$, .name$, "_");
+ .@id=atoi(.@ni$[1]);
+
+ .@q=getq(ThiefQuests_Artis);
+ .@q2=getq2(ThiefQuests_Artis);
+
+ if (.@q != .@id) {
+ speech
+ l("This wheel seems to be connected to the locked gate on the side."),
+ l("Having to reason to tinker with it, you don't.");
+ close;
+ }
+ speech
+ l("You try to move this wheel, but it is stuck. Something seems to be missing."),
+ l("Maybe some monster ate it, but what would be big enough to do that?!");
+
+ // Switch gearwheel status: 1(looted) 2(unlooted)
+ switch (.@q2) {
+ case 1:
+ // Looted but lost? D:
+ if (!countitem(Gearwheel)) {
+ mesc l("If we only had a %s.", getitemlink(Gearwheel));
+ close;
+ }
+
+ // Prompt player
+ mesc l("Should we install the %s and move it?", getitemlink(Gearwheel)), 1;
+ if (askyesno() == ASK_NO)
+ break;
+
+ delitem Gearwheel, 1;
+ setq2 ThiefQuests_Artis, 2;
+ // FALLTHROUGH
+ case 2:
+ mesc l("With the %s in place, it only takes a bit more effort to make it budge.", getitemlink(Gearwheel));
+ next;
+ closeclientdialog;
+ // Spin the wheel
+ if (!.busy) {
+ .dir = 4;
+ .busy = true;
+ initnpctimer;
+ }
+ // Open the gate
+ addtimer 500, "#ArtisThiefGate_"+.@id+"::OnOpenSesame";
+ break;
+ default:
+ }
+ close;
+
+// Done spinning?
+OnTimer4000:
+ .dir = 0;
+ .busy = false;
+ stopnpctimer;
+
+OnInit:
+ .busy = false;
+ .distance = 2;
+ end;
+}
+
+
+
+// We're missing a gate!
+001-3-0,56,44,0 duplicate(#ArtisThiefGate_1) #ArtisThiefGate_4 NPC_SEWER_GATE,2,2
+001-3-0,58,43,0 duplicate(#ArtisThiefWheel_1) #ArtisThiefWheel_4 NPC_SEWER_WHEEL
+
+
+///////////////////////////
+// The controlled warps
+001-3-0,90,61,0 script #001-3-0_90_61 NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ // No enter except when q1 and q2 matches
+ .@q=getq(ThiefQuests_Artis);
+ .@q2=getq2(ThiefQuests_Artis);
+ if (.@q != 1 || .@q2 != 2)
+ end;
+
+ // Delete previous timers. Makes easier to cheat but more reliable (FIXME)
+ deltimer("#ArtisThiefBook_0::OnBust1");
+ deltimer("#ArtisThiefBook_0::OnBust2");
+ deltimer("#ArtisThiefBook_0::OnBust3");
+ deltimer("#ArtisThiefBook_0::OnBust4");
+
+ // Archives: Begin
+ addtimer 30000, "#ArtisThiefBook_0::OnBust1";
+ warp "001-2-43", 51, 34;
+ end;
+}
+
+001-3-0,56,43,0 script #001-3-0_56_43 NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ // No enter except when quest state allows you to
+ // I thought in letting you use this passage and get busted anytime...
+ // ...........Better not. Animation will not like it, anyway.
+ .@q=getq(ThiefQuests_Artis);
+ .@q2=getq2(ThiefQuests_Artis);
+ if (.@q != 4 || .@q2 != 2)
+ end;
+
+ warp "001-2-40", 56, 40;
+ addtimer2(rand2(3000, 7000), .name$+"::OnBusted");
+ end;
+
+// Henry said to you don't use the gate, because you are not discrete enough.
+// Poor player, this is what happens for not paying attention to Henry's advise.
+OnBusted:
+ if (getmap() != "001-2-40")
+ end;
+
+ mesn l("Legion Officer");
+ mes l("HEY! How you got here!?");
+ next;
+ // Check if you'll be caught
+ if (ArrestedChances()) {
+ mesc l("Arrested!");
+ mesc l("You'll now spend a few minutes on the jail to reflect on your actions.");
+ ArrestPlayer(5);
+ } else {
+ mesc l("You're almost found out, but manage to make a quick escape!");
+ warp "001-1", 41, 36;
+ }
+ close;
+}
+
+
diff --git a/npc/001-3-0/mundane.txt b/npc/001-3-0/mundane.txt
new file mode 100644
index 00000000..58a47cb2
--- /dev/null
+++ b/npc/001-3-0/mundane.txt
@@ -0,0 +1,208 @@
+// Evol Scripts
+// Author:
+// Jesusalva
+// Description:
+// Mundane (anagram of Unnamed) is Mona's father
+// He likes to smoke cigarettes while looking for the strange sounds.
+// He is an old bowman of the Legion. He was married but it is not clear
+// what happened to his wife.
+// Lore Problems:
+// If he is missing for a week already, how is he eating anyway?
+// Also, is he afraid of blubs/rattos or of Green Slimes?
+
+// Note: Jesusalva is not someone to care a lot with code styling, and he uses
+// a convention of his own, gumi will need to cleanse the code before it gets
+// compliant with Evol Coding Style Guidelines.
+// Note 2: Logout is not handled. Making logout at an instanced map may randomly
+// warp you back to Drasil Island (000-1) or something like that. I don't know.
+// This behavior remains to be checked.
+
+001-3-0,96,66,0 script Mundane NPC_MUNDANE,{
+
+ function quest_completed
+ {
+ speech(0x0,
+ l("No matter how many times I come here, I can't find the reason for the strange sounds..."),
+ l("It is either a huge monster, some cultists, or someone throwing strange stuff into sewers."));
+ close;
+ }
+
+ function quest_inprogress
+ {
+ speech(0x0,
+ l("We need to get out of here soon. I'm scared of the Slimes!"));
+ close;
+ }
+
+ function rescue_mundane
+ {
+ speech(S_LAST_NEXT,
+ l("Scary... I am afraid of all these Slimes, Rattos and Maggots... And worse, I am lost..."),
+ l("I was an archer of the Legion and shouldn't be scared of a few maggots, but everyone has fears, right?!"),
+ l("My daughter is probably worried about me. Could you perhaps lead me out of here?"));
+
+ switch (select(l("Yes, follow me!"), l("Not now. You see, I am also afraid of Slimes and Rattos!")))
+ {
+ case 1:
+ mes "";
+ break;
+ case 2:
+ speech(S_FIRST_BLANK_LINE,
+ l("That's too bad... Although I think you're lying."),
+ l("If so, please take some courage and help me!"));
+ close;
+ break;
+ }
+ .@ID=getcharid(0);
+ .@MAP_NAME$="mona@"+str(.@ID);
+ @MUNDANE_INSTID = instance_create("001-3-0@a"+(.@ID), getcharid(3), IOT_CHAR);
+
+ // XXX - Important Note - XXX
+ // We currently have only FOUR chars to name the map. "001-3-0" or "mundane" have 7 chars, so that cannot be used.
+ // Thankfully, "mona" have 4 chars, so it's the name.
+ //
+ // Rationale: We have only 11 chars available, but 7 are reserved. So, longest name would be "abcd" + "@" + getcharid(0)
+ // Some test reported that (apparently) we have 15 whitespaces at map name start, not sure why.
+ .@instanceMapName$ = instance_attachmap("001-3-0", @MUNDANE_INSTID, 0, .@MAP_NAME$);
+
+ // This can be a bug, but most likely is because instance already exists.
+ // I don't know what would happen if we continue, so let's "penalize" the player
+ if (.@instanceMapName$ == "") {
+ speech(0x0,
+ l("Wait... You are that @@ from earlier, aren't you?", strcharinfo(0)),
+ l("If my memory serves me right, you were just defeated. Why don't you go out to buy better equipment?"));
+ close;
+ }
+
+ // You have 5 minutes to complete the quest. This does not results in failure by itself, getq2 does that
+ instance_set_timeout(300, 300, @MUNDANE_INSTID);
+ instance_init(@MUNDANE_INSTID);
+ dispbottom(l("Mona's father is right behind you. You have five minutes to bring him out of sewers!"));
+
+ // Note: Difficulty is based on your level
+ .@BLVLBOOST=BaseLevel/10;
+ areamonster(.@MAP_NAME$, 119, 51, 162, 85, strmobinfo(1, Slime), Slime, 3+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 190, 65, 193, 68, strmobinfo(1, Ratto), Ratto, 5);
+ areamonster(.@MAP_NAME$, 90, 67, 92, 72, strmobinfo(1, CaveMaggot), CaveMaggot, 3+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 99, 106, 102, 111, strmobinfo(1, Slime), Slime, 3+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 115, 93, 115, 75, strmobinfo(1, Slime), Slime, 3+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 120, 85, 7, 2, strmobinfo(1, LittleSlime), LittleSlime, 7+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 114, 65, 121, 68, strmobinfo(1, CaveMaggot), CaveMaggot, 5+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 137, 76, 130, 87, strmobinfo(1, Spider), Spider, 4+.@BLVLBOOST);
+ areamonster(.@MAP_NAME$, 98, 92, 101, 94, strmobinfo(1, Slime), Slime, 3+.@BLVLBOOST);
+
+ // Important temporary variables and move you accordingly
+ @MUNDANE_OLDX=.x;
+ @MUNDANE_OLDY=.y;
+ warp(.@MAP_NAME$, .x, .y);
+ // Move NPC as well
+ unitwarp(getnpcid(instance_npcname(.name$, @MUNDANE_INSTID)), .@MAP_NAME$, .x, .y);
+
+ setq ArtisQuests_MonaDad, 2;
+ addtimer(150, instance_npcname(.name$, @MUNDANE_INSTID)+"::OnMove");
+ updateSpotlight(true);
+ close;
+
+ }
+
+ .@q=getq(ArtisQuests_MonaDad);
+ if (.@q >= 3) quest_completed();
+ if (.@q == 2) quest_inprogress();
+ if (.@q == 1) rescue_mundane();
+ // Impossible situation, but let's not trust this. You must talk to Mona first!
+ if (.@q == 0) quest_completed();
+
+ hello;
+ end;
+
+// This functions serves two major purposes:
+// 1- Move Mundane accordingly
+// 2- Be able to determine if you brought Mundane to exit or cheat (warp, etc.)
+// NOTE: Using instance_npcname(.name$) can be unreliable at times.
+// It should work with addtimer(), but if it breaks, move @MUNDANE_INSTID to
+// the @ varspace, and use instance_npcname(.name$, @MUNDANE_INSTID)
+// That'll fix any problem when playtesting.
+OnMove:
+ getmapxy(.@m$, .@x, .@y, 0);
+ // You left the map, we don't need to move NPC anymore
+ if (!(.@m$ ~= "mona@*") && (.@m$ != "001-3-0")) {
+ disablenpc(instance_npcname(.name$, @MUNDANE_INSTID));
+ // This check shouldn't be needed but better safe than sorry
+ if (.@m$ == "001-1")
+ dispbottom l("Mundane ran straight home. He must be missing his daughter.");
+ else
+ dispbottom l("Mundane ran away, he did not trust the path you chose.");
+ end;
+ }
+ // We actually won't move the NPC to your position, but to where you were last.
+ // The NPC should not walk right in you because I thought it looks weird ingame.
+ if (.@x == @MUNDANE_OLDX && .@y == @MUNDANE_OLDY) {
+ addtimer(150, instance_npcname(.name$, @MUNDANE_INSTID)+"::OnMove");
+ end;
+ }
+
+ // movenpc() will cause NPC to "jump" to player position.
+ // npcwalkto(x, y) will make it walk to your position.
+ npcwalkto @MUNDANE_OLDX, @MUNDANE_OLDY;
+
+ // We now update the misleading @MUNDANE_OLD* variable with your current
+ // position.
+ @MUNDANE_OLDX=.@x;
+ @MUNDANE_OLDY=.@y;
+ // We must handle this every 150ms or so, which is player walk delay.
+ // When you leave the map this timer will die.
+ addtimer(150, instance_npcname(.name$, @MUNDANE_INSTID)+"::OnMove");
+ end;
+
+OnInit:
+ .distance = 3;
+ .speed = 140;
+
+// Move Mundane every Sunday, Wednesday, and Friday
+// to be less repetitive, and save also where it is
+OnSun0000:
+OnWed0000:
+OnFri0000:
+ if (.begin)
+ delcells "MundaneProtection";
+
+ // Micksha may tweak this.
+ setarray .@valid_x, 96, 132, 150, 49;
+ setarray .@valid_y, 66, 86, 118, 47;
+ .@index=rand(0,getarraysize(.@valid_x)-1);
+ movenpc .name$, .@valid_x[.@index], .@valid_y[.@index];
+
+ // Create a 3x3 monster collision block over Mundane
+ setcells .map$, .x-3, .y-3, .x+3, .y+3, 6, "MundaneProtection";
+ .begin=true;
+ end;
+
+OnInstanceInit:
+ .speed = 140; // Double-sure
+ end;
+
+}
+
+function script MundaneLogout {
+ if (getq(ArtisQuests_MonaDad) != 2) return;
+ setq ArtisQuests_MonaDad, 1;
+ return;
+}
+
+function script MundaneDeath {
+ if (getq(ArtisQuests_MonaDad) != 2) return;
+ setq ArtisQuests_MonaDad, 1;
+ dispbottom l("What a pity! You've died.");
+
+ // We must disable Mona's Dad NPC sprite if you are still on the map
+ // This will cause the NPC to "vanish", player is left to guess that he ran
+ // back to where he originally was.
+ // (ie. The NPC won't be fine without you if we have code to handle that).
+ // NOTE: Maybe we could send the NPC running back to his original position?
+ // For future thought and testing by anyone interested.
+ if (strpos(getmap(), "mona@") >= 0) {
+ disablenpc(instance_npcname(.name$, @MUNDANE_INSTID));
+ }
+ return;
+}
+
diff --git a/npc/001-3-1/_import.txt b/npc/001-3-1/_import.txt
new file mode 100644
index 00000000..3462861c
--- /dev/null
+++ b/npc/001-3-1/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-3-1: Rivercave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-3-1/_mobs.txt",
+"npc/001-3-1/_warps.txt",
+"npc/001-3-1/gates.txt",
diff --git a/npc/001-3-1/_mobs.txt b/npc/001-3-1/_mobs.txt
new file mode 100644
index 00000000..3bc6a97a
--- /dev/null
+++ b/npc/001-3-1/_mobs.txt
@@ -0,0 +1,8 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-3-1: Rivercave mobs
+001-3-1,32,21,3,0 monster Green Slime 1024,3,15000,80000
+001-3-1,27,33,0,1 monster Little Green Slime 1025,3,10000,50000
+001-3-1,23,24,0,1 monster Little Green Slime 1025,3,10000,50000
+001-3-1,26,21,0,1 monster Poison Skull 1100,1,10000,30000
+001-3-1,28,44,3,1 monster Cave Maggot 1027,4,5000,15000
+001-3-1,29,27,6,4 monster Cave Maggot 1027,5,2000,10000
diff --git a/npc/001-3-1/_warps.txt b/npc/001-3-1/_warps.txt
new file mode 100644
index 00000000..f0c3d747
--- /dev/null
+++ b/npc/001-3-1/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-3-1: Rivercave warps
+001-3-1,24,58,0 warp #001-3-1_24_58 1,0,001-3-0,162,41
+001-3-1,35,59,0 warp #001-3-1_35_59 1,0,001-3-0,172,42
diff --git a/npc/001-3-1/gates.txt b/npc/001-3-1/gates.txt
new file mode 100644
index 00000000..f3c1a038
--- /dev/null
+++ b/npc/001-3-1/gates.txt
@@ -0,0 +1,66 @@
+// Evol scripts.
+// Author:
+// Micksha, Jesusalva
+// Description:
+// The Sewer Gates, and Wheels.
+
+// Brotherhood hideout, the door opens by itself if player
+// can now talk to Sopiahalla.
+001-3-1,30,19,0 script #001-3-1_30_19 NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ .@q=getq(General_Brotherhood);
+ updateSpotlight(true);
+ if (.@q)
+ warp "001-3-2", 30, 116;
+ end;
+}
+
+// The gate itself
+001-3-1,30,20,0 script #Gate3 NPC_SEWER_GATE,2,2,{
+ .@q=getq(General_Brotherhood);
+ if (.@q)
+ mes l("This gate opens on its own for you... Should we go inside?");
+ else
+ mes l("This gate is closed.");
+ close;
+
+OnTouch:
+ .@q=getq(General_Brotherhood);
+ updateSpotlight(true);
+ // Opening
+ if (!.busy && .@q) {
+ .dir=2;
+ .busy=true;
+ initnpctimer;
+ }
+ end;
+
+// Open
+OnTimer2200:
+ .dir=4;
+ end;
+
+// Closing
+OnTimer8000:
+ .dir=6;
+ end;
+
+// Closed
+OnTimer10400:
+ .dir=0;
+ end;
+
+// Don't reopen immediately, wait a tiny bit
+OnTimer11000:
+ .busy=false;
+ stopnpctimer;
+
+// Initial configuration
+OnInit:
+ .busy=false;
+ .distance = 2;
+ end;
+}
+
diff --git a/npc/001-3-2/_import.txt b/npc/001-3-2/_import.txt
new file mode 100644
index 00000000..e627928d
--- /dev/null
+++ b/npc/001-3-2/_import.txt
@@ -0,0 +1,5 @@
+// Map 001-3-2: Hideout
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-3-2/_warps.txt",
+"npc/001-3-2/henry.txt",
+"npc/001-3-2/smuggler.txt",
diff --git a/npc/001-3-2/_warps.txt b/npc/001-3-2/_warps.txt
new file mode 100644
index 00000000..6b35b231
--- /dev/null
+++ b/npc/001-3-2/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 001-3-2: Hideout warps
+001-3-2,30,117,0 warp #001-3-2_30_117 0,0,001-3-1,30,20
diff --git a/npc/001-3-2/henry.txt b/npc/001-3-2/henry.txt
new file mode 100644
index 00000000..cfff8b56
--- /dev/null
+++ b/npc/001-3-2/henry.txt
@@ -0,0 +1,374 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// Henry, a Thief Faction member managing the Hideout in Artis.
+// Pretends to be a nice pirate.
+
+001-3-2,24,51,0 script Henry#001-3-2 NPC_HENRY,{
+ function proposeFirstQuest;
+ function reportFirstQuest;
+ function proposeSecondQuest;
+ function reportSecondQuest;
+ function proposeThirdQuest;
+ function reportThirdQuest;
+ function completedHenry;
+
+ .@q=getq(ThiefQuests_Artis);
+ switch (.@q) {
+ case 0:
+ proposeFirstQuest();
+ break;
+ case 1:
+ case 2:
+ reportFirstQuest();
+ break;
+ case 3:
+ proposeSecondQuest();
+ break;
+ case 4:
+ case 5:
+ reportSecondQuest();
+ break;
+ case 6:
+ proposeThirdQuest();
+ break;
+ case 7:
+ case 8:
+ reportThirdQuest();
+ break;
+ default:
+ completedHenry();
+ break;
+ }
+ close;
+
+///////////////////////////////////////////////////////
+function proposeFirstQuest {
+ speech
+ l("Stop! Who's there?"),
+ l("Ah, its you. Sophialla already informed me. I can help you to go to Woodland, but you also could do me a favor."),
+ l("The Legion has been on my tail for a while. They're a bit annoying, you know."),
+ l("I mean, what's wrong with smuggling goods?! The town markets would have way less stuff otherwise. You can understand me, right? Don't answer."),
+ l("Anyway, you want to get on our pirate ship, right? So you better help me out!"),
+ b(l("In Artis Townhall Archives,"))+" "+l("there is an entry about me."),
+ l("If they somehow catch me again, they'll use this entry as evidence to get me on a harsher punishment..."),
+ l("So please find my file on the archives and, I don't know, deal with it?"),
+ l("I am smart, I'll know if you lie. Anyway, just don't get caught inside the archives.");
+ //l("After messing with the Major and the Legion here, I can teach you lockpicking. Ah, and you may try to find my friend Nunia in Woodland, once you go there. She seems to be disappeared."),
+ //l("Call for Micksha and Jesusalva to implement all this, please.");
+ next;
+ mesc l("Accept this quest?"), 3;
+ if (askyesno() == ASK_YES) {
+ mesn;
+ mesq l("Great! Then I'll be counting on you!");
+ setq ThiefQuests_Artis, 1, 0, 2**rand2(17);
+ }
+ return;
+}
+
+function reportFirstQuest {
+ .@q=getq(ThiefQuests_Artis);
+ mesn;
+ mesq l("Have you already did what I asked you to?");
+ select
+ l("Not yet, but I'll be back."),
+ l("What was I supposed to do, again?"),
+ l("Yes, the file has been dealt with.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("I'm not in hurry if you're not in hurry...");
+ break;
+ case 2:
+ speech
+ l("You should invade the townhall archives - I don't care how."),
+ l("There'll be a file about an... incident... with me. Deal with the file - I also don't care how."),
+ l("Try to don't get too much attention, or they'll arrest you as well.");
+ break;
+ case 3:
+ mesn;
+ mesq l("Hm... Then tell me, what was I wearing on the file picture?");
+ next;
+ select
+ l("A fancy hat."),
+ l("A shemagh or a shawl."),
+ l("Sunglasses."),
+ l("A santa hat."),
+ l("A top hat."),
+ l("A legion armor."),
+ l("An eye patch."),
+ l("A bandit hood."),
+ rif(.@q == 2, l("There was no picture on the file."));
+ mes "";
+ if (@menu != 9) {
+ mesc l("%s lunges at you!", strnpcinfo(1));
+ mesc l("You've been stabbed!"), 1;
+ mes "";
+ mesn;
+ mesq l("Now I know you're lying; Go find my file and deal with it!");
+ percentheal -15, 0;
+ close;
+ } else {
+ // WUT How did this even happen?!
+ if (.@q != 2)
+ atcommand("@kick "+strcharinfo(0));
+
+ // TODO: Reward
+ mesn;
+ mesq l("Heh... I hope you disposed of the file.");
+ next;
+ mesn;
+ mesq l("I'll keep my end of the bargain. The Hand- I mean, we pirates will bring you to the Argaes region.");
+ next;
+ mesn;
+ mesq l("Can't bring you directly to the town because some... misunderstandings, but don't worry.");
+ next;
+ mesn;
+ mesq l("Anyway, here's some gold. I might have another task for you if you want.");
+ // Reward Reference: Lv 10
+ quest_xp(.maxLevel_1, 30, BaseLevel);
+ quest_jxp(.maxLevel_1, 30);
+ Zeny+=300;
+ setq ThiefQuests_Artis, 3;
+ // Previous state already wiped this:
+ //setq2 ThiefQuests_Artis, false; // Restart wheels
+ }
+
+ }
+ return;
+}
+
+///////////////////////////////////////////////////////
+function proposeSecondQuest {
+ speech
+ l("Ah, its you again. Welcome back."),
+ l("So, if you want to go to Hurnscald, just talk to the pirate down there."),
+ l("Anyway, I still could use your help! You see, I would like to play tricks on the legion members during the night."),
+ l("For this, I would like you to to repair the secret passage to the Legion Building."),
+ l("Don't use the passage, you're not skilled enough and will be busted! Just repair it, it'll be enough.");
+ mesc l("You suspect that he is withholding information. Do he really only wants to do pranks? But then, do you care with what he wants to do inside?");
+ next;
+ mesc l("Accept this quest?"), 3;
+ select
+ l("Actually, I wanted to ask you something."),
+ l("Yes"),
+ l("No");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Great! Then I'll be counting on you!");
+ setq1 ThiefQuests_Artis, 4;
+ close;
+ } else if (@menu == 1) {
+ mesn;
+ mesq l("Shush - No questions.");
+ next;
+ mesn;
+ mesq l("Thie-- *ahem* pirates do not reply to questions.");
+ next;
+ mesn;
+ mesq l("...What? I'm totally a pirate. Arr harr! See? Pirate.");
+ }
+ return;
+}
+
+function reportSecondQuest {
+ mesn;
+ mesq l("Have you already did what I asked you to?");
+ next;
+ select
+ l("Not yet, but I'll get to it."),
+ l("What was I supposed to do, again?"),
+ l("Yes, the deed is done.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ break;
+ case 2:
+ speech
+ l("In the sewers, there is a passage to the Legion basement."),
+ l("I want to get in there, so please do me a favor, and repair the gate. Don't try to go inside yourself, you'll be caught."),
+ l("Also - don't ask me why I want this. Thieves doesn't make questions. You better remember this!");
+ break;
+ case 3:
+ mesn;
+ mesq l("Great! I'll send a scout to check. I hope you didn't blew up everything by going there, you're not very discrete.");
+ next;
+ mes "...";
+ next;
+ .@q2=getq2(ThiefQuests_Artis);
+ if (.@q2 != 2) {
+ mesn;
+ mesq l("Nope, it is still sealed tight. Go do your job if you want a reward.");
+ break;
+ }
+ mesn;
+ mesq l("Alright - This will be... good. Anyway, I should give you a reward.");
+ next;
+ mesn;
+ mesq l("Take this %s. There is something good on it; Just use a %s.",
+ getitemlink(TreasureMap), getitemlink(IronShovel));
+
+ // Obtain the map, quest is done
+ inventoryplace TreasureMap, 1;
+ getitem TreasureMap, 1;
+ quest_jxp(.maxLevel_2, 100);
+ setq1 ThiefQuests_Artis, 6;
+
+ // Override the treasure location, if already existing
+ .@m$="001-1";
+ .@x=any(199, 200);
+ .@y=any(61,62);
+
+ shovel_addquest(.@m$, .@x, .@y, "shovel_randomtreasure");
+ ShovelQuests_AssignedMAP$=shovel_getcity(.@m$);
+ ShovelQuests_AssignedX=.@x;
+ ShovelQuests_AssignedY=.@y;
+
+ // TODO: If we add a daily legion quest, it must be "redemption"~ish
+ // That is, destroy points from all other three factions
+ // ...Also, is *this* specific code a good idea at all?
+ .@t$=faction_addrep("Legion", -15);
+ mesc .@t$;
+ .@t$=faction_addrep("Thief", 15);
+ mesc .@t$;
+ next;
+ mesn;
+ mesq l("I don't know how to get a shovel, though.");
+ next;
+ mesn;
+ mesq l("Remember: \"Use\" the map, and use the debugger (F10) or \"/where\" in chat to check your coordinates!");
+ }
+ return;
+}
+
+///////////////////////////////////////////////////////
+function proposeThirdQuest {
+ speech
+ l("Thanks for the help the other day."),
+ l("I have a beloved friend called Nunia, who handles the Thieves' Guild branch in Hurnscald."),
+ l("Bet you thought we were simple pirates, right? No smart remarks, please."),
+ l("Anyway, I haven't heard about her from quite a while, which is concerning."),
+ l("Could you please go there see if she is well?"),
+ l("I'll give you something... useful... If you want to pursue in being a thief. I'll even put a good word about you... If you manage to find our headquarters somewhere in the world, that is!");
+ next;
+ mesc l("Accept this quest?"), 3;
+ if (askyesno() == ASK_YES) {
+ mesn;
+ mesq l("Great! Then I'll be counting on you!");
+ setq1 ThiefQuests_Artis, 7;
+ close;
+ }
+ return;
+}
+
+function reportThirdQuest {
+ mesn;
+ mesq l("Have you already did what I asked you to?");
+ next;
+ select
+ l("Not yet, but I'll get to it."),
+ l("What was I supposed to do, again?"),
+ l("Yes, the deed is done.");
+ mes "";
+ switch (@menu) {
+ case 2:
+ speech
+ l("My beloved friend Nunia in Hurnscald went missing."),
+ l("I mean, I do not receive any letter from her for a while, so I got worried."),
+ l("I would like you to check how she is doing. You know, the Brotherhood could have got her and she is in need of rescue, or something else.");
+ break;
+ case 3:
+ .@q=getq(ThiefQuests_Artis);
+ mesn;
+ mesq l("Before you go on any further, I wanna see the proof that you talked with her.");
+ next;
+ if (.@q != 8) {
+ mesc l("You don't know what sort of proof he is looking for.");
+ break;
+ }
+
+ select
+ l("She has white hair, blue eyes, and always carry a big sack."),
+ l("She told me a passphrase.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Liar; Nunia is not creative enough to come up with a passphrase of her own!");
+ next;
+ mesn;
+ mesq l("Besides, if she could give you a passphrase, then I wouldn't have sent ya.");
+ break;
+ }
+
+ mesn;
+ mesq l("That's Nunia alright. So how she is doing?");
+ next;
+ mesc l("You describe to him how Nunia is supposed to lay low for a while.");
+ next;
+ mesn;
+ mesq l("Of course. I'm glad she is safe. You know, we don't really care with this Legion versus Brotherhood stifle.");
+ next;
+ mesn;
+ mesq l("The brotherhood spies here are... friendly, but mostly because our interests coincide. But in Hurnscald, where their main base is, we're enemies.");
+ next;
+ inventoryplace Lockpicks, 5;
+ mesn;
+ mesq l("Anyway, thanks for the report. I'll give you some %s.", getitemlink(Lockpicks));
+ next;
+ mesn;
+ mesq l("Whenever you find a vault, a door, or anything of interest, you can use it to pry it open.");
+ next;
+ mesn;
+ mesq l("Lockpicks are not keys, they can break quite easily. Also, you don't want anyone watching you.");
+ next;
+ mesn;
+ mesq l("If you are caught while lockpicking, you'll be arrested. So be careful.");
+ // TODO: Add a lock here where player can train without being arrested.
+ next;
+ mesn;
+ mesq l("I have other matters to attend do, so you'll have to excuse me.");
+ quest_item(.maxLevel_3, Lockpicks, 5);
+ setq1 ThiefQuests_Artis, 9;
+ break;
+ }
+ return;
+}
+
+///////////////////////////////////////////////////////
+function completedHenry {
+ mesc l("He seems to ignore you.");
+ mesc l("Probably better not disturb him.");
+ return;
+}
+
+
+///////////////////////////////////////////////////////
+OnInit:
+ .distance = 3;
+ .maxLevel_1 = 15;
+ .maxLevel_2 = 25;
+ .maxLevel_3 = 35;
+ end;
+
+OnGiantMaggot:
+ .@q=getq(ThiefQuests_Artis);
+ .@q2=getq2(ThiefQuests_Artis);
+ .@max=(.@q == 1 ? true : (.@q == 4 ? true : false));
+
+ // To drop, or not to drop...?
+ if (!.@q2 && .@max) {
+ if (rand2(10000) < 1800) {
+ getitem Gearwheel, 1;
+ setq2 ThiefQuests_Artis, true;
+ }
+ }
+
+ // Eh, whatever, continue with what you were doing, script.
+ fix_mobkill(GiantMaggot);
+ end;
+}
+
diff --git a/npc/001-3-2/smuggler.txt b/npc/001-3-2/smuggler.txt
new file mode 100644
index 00000000..965dba66
--- /dev/null
+++ b/npc/001-3-2/smuggler.txt
@@ -0,0 +1,84 @@
+// Evol scripts.
+// Author:
+// Micksha, Toams, Jesusalva
+// Description:
+// The rowboat, picking up the player on the fake pier and bringing them to
+// Argaes Westport.
+
+001-3-2,71,85,6 script Smuggler NPC_ROWBOAT_STAND_WE,{
+ function smugglerNotAuthorized;
+ function smugglerBoarding;
+ mesn;
+ mesq l("Hey dude, we actually have a pretty cool pirate ship near Artis.");
+ next;
+ mesn;
+ mesq l("This lake may look natural, but it is not quite so. We're at sea level.");
+ next;
+ .@q=getq(ThiefQuests_Artis);
+ if (.@q < 3)
+ smugglerNotAuthorized();
+ mesn;
+ mesq l("Cool, right?");
+ next;
+ select
+ l("Yes."),
+ l("So? Will you bring me to Argaes?");
+ mes "";
+ if (@menu == 2)
+ smugglerBoarding();
+ close;
+
+function smugglerNotAuthorized {
+ mesn;
+ mesq l("We smuggle not only goods, but people too. If Henry gives me the word...");
+ next;
+ mesn;
+ mesq l("Hehehe... I've heard Hurnscald is wonderful at this time of the year!");
+ close;
+ return;
+}
+
+function smugglerBoarding {
+ mesn;
+ mesq l("Sure! Hold tight.");
+ next;
+ while (.lock)
+ {
+ mesn;
+ mesq l("Just let me finish this first...");
+ next;
+ }
+ setcam (76*32), (85*32);
+ closeclientdialog;
+ .lock=true;
+ setpcblock(PCBLOCK_MOVE, true);
+ npcwalkto(76, 85);
+ sleep2(1000);
+ //setmount 1;
+ //warp "001-1", 227, 62;
+
+ PC_DEST$="Argaes";
+ @timer_navio_running = 1;
+ addtimer 210000, "#MarineShip::OnEvent"; // This route is 30s slower
+ warp "marine-2", 40, 32;
+ dispbottom l("You're smuggled aboard the Legion expedition. ACT NATURALLY!");
+
+ detachrid();
+ .dir = 2;
+ npcwalkto(71, 85);
+ sleep(1000);
+ .dir = 6;
+ .lock=false;
+ end;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ .speed = 175;
+ .alwaysVisible = true;
+ .lock = false;
+ end;
+
+}
+
diff --git a/npc/008-1-1/_import.txt b/npc/008-1-1/_import.txt
new file mode 100644
index 00000000..46f9ce78
--- /dev/null
+++ b/npc/008-1-1/_import.txt
@@ -0,0 +1,11 @@
+// Map 008-1-1: Woodland
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-1-1/_mobs.txt",
+"npc/008-1-1/_warps.txt",
+"npc/008-1-1/cutscene.txt",
+"npc/008-1-1/galimatia.txt",
+"npc/008-1-1/hal.txt",
+"npc/008-1-1/koga.txt",
+"npc/008-1-1/morcant.txt",
+"npc/008-1-1/sign.txt",
+"npc/008-1-1/soldiers.txt",
diff --git a/npc/008-1-1/_mobs.txt b/npc/008-1-1/_mobs.txt
new file mode 100644
index 00000000..928a2c6d
--- /dev/null
+++ b/npc/008-1-1/_mobs.txt
@@ -0,0 +1,38 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1-1: Woodland mobs
+008-1-1,173,86,25,5 monster Forest Maggot 1028,12,500,2500
+008-1-1,132,56,7,5 monster Forest Maggot 1028,5,500,2500
+008-1-1,74,59,9,16 monster Butterfly 1032,4,20000,10000
+008-1-1,63,73,11,5 monster Maggot 1026,7,500,10000
+008-1-1,206,87,6,4 monster Mouboo 1023,3,30000,60000
+008-1-1,131,45,0,0 monster Beehive 1056,1,30000,100000
+008-1-1,156,51,10,4 monster Alizarin Plant 1037,3,1000,25000
+008-1-1,167,61,2,2 monster Pink Flower 1034,1,100,10000
+008-1-1,154,176,9,7 monster Silkworm 1040,4,3000,6000
+008-1-1,162,78,6,3 monster Gamboge Plant 1038,2,1000,10000
+008-1-1,197,67,7,5 monster Cobalt Plant 1039,2,1000,30000
+008-1-1,165,109,2,2 monster Pink Flower 1034,1,100,10000
+008-1-1,217,62,2,2 monster Pink Flower 1034,1,100,10000
+008-1-1,119,66,2,2 monster Pink Flower 1034,1,100,10000
+008-1-1,112,75,2,2 monster Pink Flower 1034,1,100,10000
+008-1-1,110,46,3,2 monster Mauve Plant 1036,3,1000,2000
+008-1-1,159,93,9,7 monster Silkworm 1040,4,3000,6000
+008-1-1,62,36,7,7 monster Mouboo 1023,3,30000,60000
+008-1-1,126,45,0,0 monster Beehive 1056,1,30000,100000
+008-1-1,121,45,0,0 monster Beehive 1056,1,30000,100000
+008-1-1,163,178,2,1 monster Red Rose 1062,1,50000,10000
+008-1-1,158,191,3,1 monster Yellow Rose 1060,1,20000,5000
+008-1-1,166,184,1,1 monster Blue Rose 1061,1,100000,20000
+008-1-1,137,86,11,16 monster Butterfly 1032,8,10000,10000
+008-1-1,75,41,14,4 monster Silkworm 1040,3,9000,6000
+008-1-1,122,75,8,4 monster Forest Maggot 1028,3,50000,2500
+008-1-1,161,67,45,11 monster Mouboo 1023,3,20000,125000
+008-1-1,180,77,11,21 monster Log Head 1031,3,10000,15000
+008-1-1,149,77,99,15 monster Mana Bug 1035,11,10000,20000
+008-1-1,144,107,11,5 monster Bee 1029,3,5000,10000
+008-1-1,149,59,11,5 monster Bee 1029,3,5000,10000
+008-1-1,156,183,11,5 monster Bee 1029,3,5000,10000
+008-1-1,161,186,9,7 monster Bandit 1063,2,9000,18000
+008-1-1,157,172,5,15 monster Robin Bandit 1064,2,9000,18000
+008-1-1,156,177,10,15 monster Small Frog 1086,2,3000,30000
+008-1-1,169,74,30,23 monster Squirrel 1041,5,10000,30000
diff --git a/npc/008-1-1/_warps.txt b/npc/008-1-1/_warps.txt
new file mode 100644
index 00000000..cbf66f26
--- /dev/null
+++ b/npc/008-1-1/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1-1: Woodland warps
+008-1-1,247,85,0 warp #008-1-1_247_85 0,1,008-1,21,85
+008-1-1,51,57,0 warp #008-1-1_51_57 0,0,008-2-32,40,37
+008-1-1,181,198,0 warp #008-1-1_181_198 1,0,009-1,180,32
diff --git a/npc/008-1-1/cutscene.txt b/npc/008-1-1/cutscene.txt
new file mode 100644
index 00000000..a9d39a6c
--- /dev/null
+++ b/npc/008-1-1/cutscene.txt
@@ -0,0 +1,180 @@
+// TMW Script
+// Author:
+// Jesusalva
+// Description:
+// Cutscenes for Main Story
+
+008-1-1,42,63,0 script #MQ2Cutscene NPC_HIDDEN,0,1,{
+ end;
+
+OnTouch:
+ .@q=getq(General_Narrator);
+ if (.@q != 2)
+ end;
+ if (getmap() != "008-1-1")
+ end;
+ // Cutscene time!
+ // m (from main quest) 02 map 1
+ .@mapn$="m021@"+getcharid(0);
+ .@mapx$="m022@"+getcharid(0);
+ // Build instance if it doesn't exists or has been reallocated
+ // (This only happens if you escape the map - edge case scenarios)
+ if (instanceowner(@mainquestinst) != getcharid(3)) {
+ @mainquestinst = instance_create("m102@a"+getcharid(0), getcharid(3), IOT_CHAR);
+ instance_attachmap("008-1-1", @mainquestinst, false, .@mapn$);
+ instance_attachmap("008-2-32", @mainquestinst, false, .@mapx$);
+ // Instance lasts 60 minutes
+ instance_set_timeout(3600, 3600, @mainquestinst);
+ instance_init(@mainquestinst);
+ } else {
+ // Restart instance timer if it already exists
+ instance_set_timeout(3600, 3600, @mainquestinst);
+ }
+ getmapxy(.@m$, .@x, .@y, 0);
+ warp(.@mapn$, .@x, .@y);
+ addtimer(500, instance_npcname(.name$, @mainquestinst)+"::OnBegin");
+ end;
+
+OnBegin:
+ .@n$=instance_npcname(.name$);
+ .@mc$=instance_npcname("Morcant");
+
+ // Freeze player
+ // (M+ may render this incorrectly but it is not my job to care with that)
+ setpcblock(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM|PCBLOCK_MOVE, true);
+ sc_start(SC_STUN, 360000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK);
+
+ // Begin moving Morcant
+ npcwalkto(58, 64, .@mc$);
+ sleep2(3000);
+ getmapxy(.@m$, .@x, .@y, 0);
+ npcwalkto(.@x + 1, .@y, .@mc$);
+ sleep2(1000);
+ unitwarp(getnpcid(.@mc$), .@m$, .@x + 1, .@y); // FIXME PLACEHOLDER
+ npctalk l("Hoho!"), .@mc$;
+ sleep2(2500);
+ npctalk l("Look what the shore brought me!"), .@mc$;
+ sleep2(3000);
+ npctalk l("Rarely anyone uses this port."), .@mc$;
+ sleep2(3000);
+ npctalk l("...Well, anyone adhering to the law, at least! Hahahah!"), .@mc$;
+ sleep2(3000);
+ npctalk l("Anyway, come in! You must be hungry."), .@mc$;
+ sleep2(3000);
+ npcwalkto(51, 57, .@mc$);
+ sleep2(1000);
+ sc_end(SC_STUN);
+ setpcblock(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM|PCBLOCK_MOVE, false);
+ dispbottom col(l("1-1. Follow Morcant into his house."), 1);
+ sleep2(500);
+ .@mapx$="m022@"+getcharid(0);
+ unitwarp(getnpcid(.@mc$), .@mapx$, 40, 24);
+ end;
+}
+
+// Series 2
+008-1-1,51,58,0 script #MQ2Cutscene2 NPC_HIDDEN,0,1,{
+ end;
+OnTouch:
+ if (getmap() == "008-1-1") end;
+ .@n$=instance_npcname(.name$);
+ .@mapx$="m022@"+getcharid(0);
+ warp(.@mapx$, 40, 36);
+ addtimer(3000, .@n$+"::OnStunlock");
+ end;
+
+OnStunlock:
+ .@n$=instance_npcname(.name$);
+ addtimer(300, .@n$+"::OnBegin");
+ // Freeze player
+ // (M+ may render this incorrectly but it is not my job to care with that)
+ setpcblock(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM|PCBLOCK_MOVE, true);
+ sc_start(SC_STUN, 360000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK);
+ end;
+
+OnBegin:
+ .@n$=instance_npcname(.name$);
+ .@mc$=instance_npcname("Morcant");
+ .@tm$=instance_npcname("Thamas");
+ npctalk l("Welcome to my humble abode."), .@mc$;
+ sleep2(500);
+ npctalk l("Who is that fellow?"), .@tm$;
+ sleep2(2500);
+ npctalk l("Thamas, this is a stowaway who reached here from Artis."), .@mc$;
+ sleep2(2500);
+ npctalk l("Yes, I remember."), .@tm$;
+ sleep2(3000);
+ npctalk l("Anyway, I assume you're trying to get into Hurnscald?"), .@mc$;
+ sleep2(2100);
+ npctalk l("Really? You should be careful, then."), .@tm$;
+ sleep2(2500);
+ npctalk l("Hurnscald is under the domain of the Brotherhood."), .@tm$;
+ sleep2(3000);
+ npctalk l("Shaddy fellas, I do not trust them the sightliest."), .@tm$;
+ sleep2(3500);
+ npctalk l("*ahem*!"), .@mc$;
+ sleep2(2000);
+ npctalk l("Hurnscald is just east of here."), .@mc$;
+ sleep2(2000);
+ npctalk l("Keep following the road, you can't miss it."), .@mc$;
+ sleep2(3000);
+ npctalk l("Do not venture into south, though."), .@mc$;
+ sleep2(2000);
+ npctalk l("It is haunted."), .@mc$;
+ sleep2(2500);
+ //atcommand("@refresh"); // FIXME -> Hercules upstream broke @refresh
+ // TODO FIXME: Check if x-1 is a collision, move to x+1 if it is
+ getmapxy(.@m$, .@x, .@y, 0);
+ npcwalkto(.@x - 1, .@y, .@mc$);
+ sleep2(1000);
+ unitwarp(getnpcid(.@mc$), .@m$, .@x - 1, .@y); // FIXME PLACEHOLDER
+ npctalk col(l("*Hey, psst.*"), 9), .@mc$;
+ sleep2(1000);
+ npctalk col(l("*I assume you're here for the Brotherhood, right?*"), 9), .@mc$;
+ sleep2(2500);
+ npctalk col(l("*Reaching Hurnscald, look for a girl called Airlia.*"), 9), .@mc$;
+ sleep2(2500);
+ npctalk col(l("*Whisper her the... password, and she'll lead you to Jonatas.*"), 9), .@mc$;
+ sleep2(3100);
+ npctalk col(l("*I don't know why Sophiahalla sent you here...*"), 9), .@mc$;
+ sleep2(2200);
+ npctalk col(l("*But I am just a retired merchant, hohoho!*"), 9), .@mc$;
+ sleep2(2200);
+ npctalk l("Anyway, that's it. Here, have a bowl of stew, Morcant special!"), .@mc$;
+ sleep2(2500);
+ npctalk l("I'll be back to the port, so see you later!"), .@mc$;
+ npcwalkto(40, 38, .@mc$);
+ sleep2(2000);
+ .@mapx$="m021@"+getcharid(0);
+ unitwarp(getnpcid(.@mc$), .@mapx$, 51, 58);
+ sc_end(SC_STUN);
+ setpcblock(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM|PCBLOCK_MOVE, false);
+ sleep2(1000);
+ getmapxy(.@m$, .@x, .@y, 0);
+ warp "008-2-32", .@x, .@y;
+ getitembound SailorStew, 1, IBT_ACCOUNT;
+ setq General_Narrator, 3;
+ end;
+}
+
+// WHAT ARE YOU DOING
+008-1-1,83,65,0 script #MQ2CutsceneWAYD NPC_HIDDEN,0,10,{
+ end;
+
+OnTouch:
+ if (getmap() == "008-1-1") end;
+ // What are you doing?!
+ slide 51, 63;
+ mesc l("I really should follow Morcant into his house.");
+ close;
+}
+
+008-2-32,40,37,0 script #MQ2Cutscene2WAYD NPC_HIDDEN,1,0,{
+ end;
+OnTouch:
+ if (getmap() == "008-2-32") end;
+ slide 40, 36;
+ dispbottom l("But you just arrived! Seriously. Stop.");
+ end;
+}
+
diff --git a/npc/008-1-1/galimatia.txt b/npc/008-1-1/galimatia.txt
new file mode 100644
index 00000000..6b3bfabe
--- /dev/null
+++ b/npc/008-1-1/galimatia.txt
@@ -0,0 +1,431 @@
+// Evol scripts.
+// Author:
+// Micksha
+// The other player I've forgot the name
+// Livio
+// Jesusalva
+// Description:
+// Galimatia the beekeeper.
+// KEEP item_db.conf updated as well
+
+function script usePurificationPotion {
+ // Check quest status, if not in a quest provide default item behaviour
+ if (getq(ArgaesQuest_Galimatia) == 1) {
+ // Do as requested by quest
+ if (isin("008-1-1", 95, 45, 99, 48)) {
+ setq(ArgaesQuest_Galimatia, 2);
+ message strcharinfo(0), l("Done. Maybe it's time to ask Galimatia what to do now.");
+ delitem PurificationPotion, 1;
+ } else {
+ message strcharinfo(0), l("Hmm... I'm sure that is not the right place to put it.");
+ return true;
+ }
+ } else return false;
+}
+
+function script useFertilityPotion {
+ // Check quest status, if not in a quest provide default item behaviour
+ if (getq(ArgaesQuest_Galimatia) == 3) {
+ // Do as requested by quest
+ if (isin("008-1-1", 95, 45, 99, 48)) {
+ setq(ArgaesQuest_Galimatia, 4);
+ message strcharinfo(0), l("All right! I've poured even this one..");
+ delitem FertilityPotion, 1;
+ } else {
+ message strcharinfo(0), l("Hmm... This one is supposed to be poured where the other one were.");
+ return true;
+ }
+ } else return false;
+}
+
+// ------------------------------------
+008-1-1,113,59,0 script Galimatia NPC_GALIMATIA,{
+ function advanceQuest;
+ function NPCdemandsIngredients;
+ function QuestPart0;
+ function QuestPart1;
+ function QuestPart2;
+ function QuestPart3;
+ function QuestPart4;
+ function QuestPart5;
+ function QuestPart6;
+ function galimatiaQuestDaily;
+
+ switch(getq(ArgaesQuest_Galimatia)) {
+ case 0: QuestPart0(); break;
+ case 1: QuestPart1(); break;
+ case 2: QuestPart2(); break;
+ case 3: QuestPart3(); break;
+ case 4: QuestPart4(); break;
+ case 5: QuestPart5(); break;
+ case 6: QuestPart6(); break;
+ case 7: galimatiaQuestDaily(); break;
+ default:
+ mesq l("[Invalid quest status! %d, check script]", getq(ArgaesQuest_Galimatia));
+ }
+ close;
+
+
+// FIXME comment better
+// Makes NPC to ask for ingredients
+function NPCdemandsIngredients {
+ mesq l("Fine. The land is healthy now but nothing will grow yet. This time I need you to get:");
+ printIngredients(.REQ1_INGREDIENTS, .REQ1_INGREDIENTS_AMOUNT);
+ mesq l("So making a %s will make things easier.", getitemlink(.REQ1_OUTPUT));
+ if (NPCcrafting(
+ .REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT,
+ .REQ0_OUTPUT, .REQ0_OUTPUT_AMOUNT,
+ l("Okay. Give me a second..."),
+ l("Nope. You don't have enough ingredients for that."),
+ l("I can't give you nothing if you don't leave some room for it!")
+ )
+ ) {
+ advanceQuest();
+ mesq l("You must now pour it over the land again in the same spot.");
+ }
+ close;
+ return;
+}
+
+
+//-----------------
+
+function advanceQuest {
+ setq(ArgaesQuest_Galimatia, getq(ArgaesQuest_Galimatia) + 1);
+ return;
+}
+
+/*
+You arrive and get off the boat and walk down a path to a farm where there is a Bee farmer named Galimatia.
+Her Bees have moved to somewhere else, because his field of flowers has died from a blight. He needs some way to still gather honey to earn his living.
+Galimatia needs to tend to other work and can’t get away, so she asks player for some help. She sends player after 5 Pink Petals and 1 Bottle of Water.
+*/
+
+function QuestPart0 {
+ speech
+ l("Hello."),
+ l("If only someone could help me to make my flowers bloom again."),
+ l("I just dont know what to do. Perhaps all gets better when I stay here, whining and waiting. Please, leave me alone.");
+ next;
+
+ select(
+ l("What about making some fertilizing-something?"),
+ l("I don't have time to spend on flowers.")
+ );
+ mes "";
+ mesn;
+
+ switch(@menu) {
+ case 1:
+ mesq l("All right! I need you to get:");
+ printIngredients(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ mesq l("So I can make a %s out of it.", getitemlink(.REQ0_OUTPUT));
+ if (NPCcrafting(
+ .REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT,
+ .REQ0_OUTPUT, .REQ0_OUTPUT_AMOUNT,
+ l("Have you got those things with you?"),
+ l("Okay. Give me a second..."),
+ l("Nope. You don't have enough ingredients for that."),
+ l("I can't give you nothing if you don't leave some room for it!")
+ )
+ ) {
+ advanceQuest();
+ mesq l("You must now pour it over the land.");
+ }
+ close;
+ break;
+ default:
+ // FIXME This got to be improved in other script parts as well
+ mesq
+ any(
+ l("Gave up already?"),
+ l("Okay..."),
+ l("Go stay afk in TMW Legacy if you don't want to make yourself useful."),
+ l("Hehe, hehe. Well, come back if you change your mind."
+ )
+ );
+ close;
+ }
+ return;
+}
+
+/*
+She made a Purification Potion out of ingredients to heal the land and gives it to the player and says it must be poured over the land (marked in some way. Like in the Orum and Waric follow-up quest).
+*/
+function QuestPart1 {
+ if(checkForItems(.REQ0_OUTPUT, .REQ0_OUTPUT_AMOUNT)) {
+ speech
+ l("What's up? You want me to show how to open a bottle and pour its content on the ground?");
+ } else {
+ speech
+ l("Why you don't have a %s with you? You need me to make another one?", getitemlink(.REQ0_OUTPUT));
+ if (askyesno() == ASK_NO) {
+ mesq l("Come on, stop wasting my time!");
+ close;
+ } else{
+ if (NPCcrafting(
+ .REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT,
+ .REQ0_OUTPUT, .REQ0_OUTPUT_AMOUNT,
+ l("Again, do you have what I need to make that?"),
+ l("Here we go again..."),
+ l("No! Have you already forgot what I need for it?"),
+ l("You don't even have the space in your inventory to carry it!!! Oh, man you are a disaster...")
+ )
+ ) {
+ // FIXME Put some messages about making again the potion so the NPC can look different and react like it was somewhat disturbed by player failure
+ mesq l("Remember: you must pour it over the land.");
+ }
+ }
+ }
+ close;
+ return;
+}
+
+/*
+If you weren't able to trash the potion, the land is now healed, but nothing grows. Galimatia is happy the land is well and wants to help. She sends player to get 1 Bottle of Water, 10 Maggot Slime and 5 Mauve Herb. From this she makes a Fertility Potion. Again she gives it to the player and says it must be poured in the same place. Player uses it and the effect comes again.
+*/
+
+
+function QuestPart2 {
+ mesn;
+ mesq l("Fine. The land is healthy now but nothing will grow yet. This time I need you to get:");
+ printIngredients(.REQ1_INGREDIENTS, .REQ1_INGREDIENTS_AMOUNT);
+ mesq l("So making a %s will make things easier.", getitemlink(.REQ1_OUTPUT));
+ if (NPCcrafting(
+ .REQ1_INGREDIENTS, .REQ1_INGREDIENTS_AMOUNT,
+ .REQ1_OUTPUT, .REQ1_OUTPUT_AMOUNT,
+ l("Have you got what we need?"),
+ l("Here it is!"),
+ l("No! You haven't!"),
+ l("I can't give you nothing if you don't leave some room for it!")
+ )
+ ) {
+ advanceQuest();
+ mesq l("You must now pour it over the land again in the same spot.");
+ }
+ close;
+ return;
+}
+
+
+function QuestPart3 {
+ if(checkForItems(.REQ1_OUTPUT, .REQ1_OUTPUT_AMOUNT)) {
+ speech
+ l("Come on pal, what's the matter?");
+ } else {
+ speech
+ l("Got drunk with the %s? You need me to make another one?", getitemlink(.REQ1_OUTPUT));
+ if (askyesno() == ASK_NO) {
+ mesn;
+ mesq l("Come on, stop wasting my time!");
+ close;
+ } else{
+ if (NPCcrafting(
+ .REQ1_INGREDIENTS, .REQ1_INGREDIENTS_AMOUNT,
+ .REQ1_OUTPUT, .REQ1_OUTPUT_AMOUNT,
+ l("Again, do you have what I need to make that?"),
+ l("Here we go again..."),
+ l("No! Have you already forgot what I need for it?"),
+ l("I can't give you nothing if you don't leave some room for it!")
+ )
+ ) {
+ // FIXME Put some messages about making again the potion so the NPC can look different and react like it was somewhat disturbed by player failure
+ mesq l("Remember: you must now pour it over the land.");
+ }
+ }
+ }
+ close;
+ return;
+}
+
+/*
+Part 3
+Flowers now can be planted. Therefore Galimatia needs help of Blossom. She sends the player to her to get 5 packages of flower seeds.
+NOTE: Flower seeds are dropped directly from Clover Patches, however grass seeds are more common.
+*/
+
+function QuestPart4 {
+ speech
+ l("Thanks for the help earlier. The soil is now fertile thanks to your efforts."),
+ l("Do you know Blossom? She is the flower girl. Bees won't come without flowers."),
+ l("So, now I need %d %s.", .REQ2_INGREDIENTS_AMOUNT, getitemlink(.REQ2_INGREDIENTS));
+ next;
+ // We don't take player items without asking
+ mesc l("Deliver items to Blossom?");
+ if (askyesno() == ASK_NO) close;
+ if(checkForItems(.REQ2_INGREDIENTS, .REQ2_INGREDIENTS_AMOUNT)) {
+ advanceQuest();
+ speech
+ l("Nice, gimme that!"),
+ l("I'll go plant them. Now go, maybe I need your help again later.");
+ } else {
+ speech
+ l("Go get some!");
+ }
+ close;
+ return;
+}
+
+/*
+The fields are in bloom and the Bees hard at work bringing stuff to the Beehives.
+Galimatia is thankful for your help and offers to pay you a larger reward if you help her collect honey as well.
+Honey is dropped by Beehives. To gather honey from Beehives you must defeat the bees protecting it, which will attack you when you attack their hive. When you kill a hive, 2 - 3 aggro bees spawn. The player must kill them (which is not so easy). (Some hives don't have Honey and some do - 50% drop rate should do the trick). The hive is a mob just like the pink flowers. Four honey jars complete the quest.
+Galimatia reassures you that these are giant bees and they will rebuild their hives quickly so it's not all as cruel as it may seem.
+
+Galimatia gives the player their reward: Player must select a simple Magic Wand (provides Healing Spell) or a Mana Torch (provides Fire Attack Spell), both can be used as a torch to keep angry bees away and a Jar of Honey.
+*/
+
+function QuestPart5 {
+ speech
+ l("Nice job."),
+ l("I've heard bees are scared of fire, you know."),
+ l("So, what do you want?"),
+ l("A %s or a %s?", getitemlink(.QUESTPRIZES[0]) , getitemlink(.QUESTPRIZES[1]));
+ select(
+ l("I want the %s!", getitemname(.QUESTPRIZES[0])),
+ l("A %s?!? Cool!!!", getitemname(.QUESTPRIZES[1]))
+ );
+ if (!checkweight(.QUESTPRIZES[@menu-1], .QUESTPRIZES_AMOUNT[@menu-1])) {
+ mesq l("I can't give you a prize if you are overburdened. Make room in your inventory!");
+ }
+ else{
+ getitem(.QUESTPRIZES[@menu-1], .QUESTPRIZES_AMOUNT[@menu-1]);
+ advanceQuest();
+ mesq l("Use those wisely and use safety glasses.");
+ }
+ close;
+ return;
+}
+
+/*
+Part 6 (Extra Quest)
+This enables the player to receive a Rose Hat. Fighting the flowers that were just planted, the player will receive roses and / or tulips as a drop. in Part 3 Blossom may mention that she always is happy about receiving the rare Blue Rose. She trades the Rose Hat for 10 Blue Roses and a preparation fee of 1.000 GP. She offer this only after everything before is finished.
+*/
+
+function QuestPart6 {
+ mesn;
+ mesq l("Hello again! Do you want me to exchange %d %s and %d GP for a %s?",
+ .REQ3_INGREDIENTS_AMOUNT[0], getitemlink(.REQ3_INGREDIENTS[0]),
+ .REQ3_COST, getitemlink(.REQ3_OUTPUT)
+ );
+ if (askyesno() == ASK_NO) {
+ mesq l("As you wish.");
+ close;
+ } else {
+ if(Zeny>=.REQ3_COST) {
+ if(NPCcrafting(
+ .REQ3_INGREDIENTS, .REQ3_INGREDIENTS_AMOUNT,
+ .REQ3_OUTPUT, .REQ3_OUTPUT_AMOUNT,
+ l("Do you have what I need?"),
+ l("Have fun!"),
+ l("Nope. I wont exchange for such less."),
+ l("I can't give you nothing if you don't leave some room for it!")
+ )) {
+ Zeny-=(.REQ3_COST);
+ advanceQuest();
+ }
+ } else {
+ mesq l("Ain't working for free, pal!");
+ }
+ }
+ close;
+ return;
+}
+
+/*
+Daily Part
+Allows players to sell Honey for Galimatia
+*/
+function galimatiaQuestDaily {
+ // DailyQuest(lvl, cost, count, item)
+ DailyQuest(10, 3, 1, Honey);
+ return;
+}
+
+OnInit:
+ // NPC ITEM REQUESTS
+ setarray(.REQ0_INGREDIENTS,
+ BottleOfWater,
+ PinkPetal
+ );
+ setarray(.REQ0_INGREDIENTS_AMOUNT,
+ 1,
+ 5
+ );
+ .REQ0_OUTPUT = PurificationPotion;
+ .REQ0_OUTPUT_AMOUNT = 1 ;
+
+ setarray(.REQ1_INGREDIENTS,
+ BottleOfWater,
+ MaggotSlime,
+ MauveHerb
+ );
+ setarray(.REQ1_INGREDIENTS_AMOUNT,
+ 1,
+ 10,
+ 5
+ );
+ .REQ1_OUTPUT = FertilityPotion;
+ .REQ1_OUTPUT_AMOUNT = 1;
+
+ setarray(.REQ2_INGREDIENTS, FlowerSeeds);
+ setarray(.REQ2_INGREDIENTS_AMOUNT, 5);
+
+ setarray(.QUESTPRIZES,
+ TrainingWand,
+ ManaTorch
+ );
+ setarray(.QUESTPRIZES_AMOUNT,
+ 1,
+ 1
+ );
+
+ setarray(.REQ3_INGREDIENTS, ABlueRose);
+ setarray(.REQ3_INGREDIENTS_AMOUNT, 10);
+ .REQ3_COST = 1000;
+ .REQ3_OUTPUT = RoseHat;
+ .REQ3_OUTPUT_AMOUNT = 1;
+
+ .distance = 4;
+ end;
+}
+
+// ------------------------------------
+// Bees Hotspot
+008-1-1,93,46,0 script #GalimatiaInst NPC_HIDDEN,0,1,{
+ end;
+
+// Transport
+OnTouch:
+ if (getq(ArgaesQuest_Galimatia) >= 5) {
+ if (getmap() == "008-1-1")
+ warp "gali@matia", 94, 46;
+ else
+ warp "008-1-1", 92, 46;
+ }
+ end;
+
+// Populate
+OnInstanceInit:
+ areamonster("gali@matia", 95, 45, 97, 46, strmobinfo(1, RedRose), RedRose, 1, "#GalimatiaInst::OnRed");
+ areamonster("gali@matia", 95, 47, 99, 48, strmobinfo(1, YellowRose), YellowRose, 1, "#GalimatiaInst::OnYellow");
+ monster("gali@matia", 99, 45, strmobinfo(1, BlueRose), BlueRose, 1, "#GalimatiaInst::OnBlue");
+ end;
+
+// Respawn
+OnRed:
+ sleep(60000);
+ areamonster("gali@matia", 95, 45, 97, 46, strmobinfo(1, RedRose), RedRose, 1, "#GalimatiaInst::OnRed");
+ end;
+
+OnBlue:
+ sleep(120000);
+ monster("gali@matia", 99, 45, strmobinfo(1, BlueRose), BlueRose, 1, "#GalimatiaInst::OnBlue");
+ end;
+
+OnYellow:
+ sleep(25000);
+ areamonster("gali@matia", 95, 47, 99, 48, strmobinfo(1, YellowRose), YellowRose, 1, "#GalimatiaInst::OnYellow");
+ end;
+}
+
diff --git a/npc/008-1-1/hal.txt b/npc/008-1-1/hal.txt
new file mode 100644
index 00000000..88b93a79
--- /dev/null
+++ b/npc/008-1-1/hal.txt
@@ -0,0 +1,131 @@
+// Evol scripts.
+// Author:
+// Livio
+// Micksha
+// Description:
+// Hal, former Captain of the Legion.
+// Following: https://gitlab.com/evol/evol-narrative/-/raw/e819b2a213802f6ded9f9b7efd18b09b0bc27570/Storylines/4.West%20Argaes.txt
+// THIS IS A PLACEHOLDER!
+
+008-1-1,58,27,0 script Hal NPC_HAL,{
+// Private function declarations
+function advanceQuest;
+function advanceQuest {
+ setq(General_CptHal, getq(General_CptHal) + 1);
+ return;
+}
+
+function QuestPart0;
+function QuestPart1;
+function QuestPart2;
+function QuestPart3;
+function QuestPart4;
+function QuestPart5;
+
+ switch(getq(General_CptHal)) {
+ case 0: QuestPart0(); break;
+ case 1: QuestPart1(); break;
+ case 2: QuestPart2(); break;
+ case 3: QuestPart3(); break;
+ case 4: QuestPart4(); break;
+ case 5: QuestPart5(); break;
+ default:
+ mesq l("[Invalid quest status: %d, check script]", getq(General_CptHal));
+ }
+ close;
+
+// Haven't met Thamas? MOVE ALONG CITIZEN!!!
+function QuestPart0 {
+ speech l("MOVE ALONG CITIZEN!!!");
+// l("I was just having a nap, now WildX summons me to stand here! What a crap."),
+// l("Please, ask elanore to !slap him for me when you see them.");
+ close;
+}
+
+function QuestPart1 {
+ speech l("MOVE ALONG C...");
+ select l("Hey, hey... I've been talking with one of your comrades, Thamas.");
+ speech l("So what?");
+ select l("What's so special about a mission assigned to a picky soldier?");
+ mesq l("You see the soldiers staring each other and then at you.");
+ speech l("You think that I'm going to disclose that to you???");
+ select
+ l("I just want to earn something to make a living."),
+ l("Ah, so special mission is secret mission too? Sorry if I've bothered you.");
+
+ if (@menu==1) {
+ speech l("You look like anything but military personnel... Okay since the Brotherhood will discharge their quivers on us at the very first encounter I guess that we can make a good use of you.");
+ speech l("We cannot get close to Hurnscald in Legion uniforms so we may need you to get some supplies. However, stay away from Hurnscald if you can.");
+ speech l("Bring us some food supplies to help us feed the troops. We need:");
+ printIngredients(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ next;
+ advanceQuest();
+ }
+ speech l("Now, get out of my face.");
+ close;
+}
+
+function QuestPart2 {
+ if (checkForItems(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT)){
+ if (NPCcrafting(
+ .REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT,
+ .REQ0_OUTPUT, .REQ0_OUTPUT_AMOUNT,
+ l("Have you got those things with you?"),
+ l("Fine. Here is your reward."),
+ l("Go find those supplies! Don't waste my time!"),
+ l("Your inventory is full, make room if you want your reward!")
+ )
+ )
+ {
+ BaseExp += 15 * BaseLevel;
+ Zeny += 150;
+ getitem(.REQ0_OUTPUT, .REQ0_OUTPUT_AMOUNT);
+ advanceQuest();
+ speech l("Now I need you to explore the area looking for Sergeant Ryan. I'm not having any report from him since a lot of time.");
+ speech l("I want you to go find him. He should not be that far from here.");
+ }
+ }
+}
+
+function QuestPart3 {
+ speech l("Any luck finding Ryan?");
+ select l("Negative.");
+ speech l("Scout the zone better! He must be somewhere nearby.");
+ close;
+}
+
+function QuestPart4 {
+ speech l("So?");
+ select l("Found priv... Ehm, I've found Sergeant Ryan. He is hurt and cannot walk right now.");
+ speech l("I don't have enough men to send after Sergeant Ryan. Provide him some sort of support until he recovers.");
+ select l("Roger that. Private %s, over!", strcharinfo(PC_NAME));
+ close;
+}
+
+
+function QuestPart5 {
+ select l("Good news! Sgt.Ryan is fine now and is going to go on with his mission.");
+ speech l("Well done.");
+ next;
+ speech l("MOVE ALONG!!! I don't need you anymore.");
+ close;
+}
+
+OnInit:
+ // NPC ITEM REQUESTS
+ setarray(.REQ0_INGREDIENTS,
+ MoubooSteak,
+ MoubooMilk,
+ Honey
+ );
+ setarray(.REQ0_INGREDIENTS_AMOUNT,
+ 5,
+ 5,
+ 1
+ );
+ .REQ0_OUTPUT = BottleOfWater;
+ .REQ0_OUTPUT_AMOUNT = 1 ;
+
+ .distance = 4;
+ end;
+} \ No newline at end of file
diff --git a/npc/008-1-1/koga.txt b/npc/008-1-1/koga.txt
new file mode 100644
index 00000000..9908ff40
--- /dev/null
+++ b/npc/008-1-1/koga.txt
@@ -0,0 +1,34 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// The Koga in Argaes
+// THIS IS A PLACEHOLDER!
+
+008-1-1,27,60,0 script Gema IV#008-1-1 NPC_LA_MARINE,{
+ function kogaWrongMap;
+ if (getmap() != "008-1-1")
+ kogaWrongMap();
+
+ mesc l("Returning to Artis is free, but coming back to Argaes after doing this may not be so.");
+ next;
+ mesc l("Return to Artis?");
+ if (askyesno() == ASK_YES)
+ {
+ closeclientdialog;
+ setmount 0;
+ EnterTown("Artis", true);
+ dispbottom l("The travel is a blur, you cannot remember much of it before reaching %s.", l("Artis"));
+ }
+ close;
+
+function kogaWrongMap {
+ mesc l("I've just arrived here. I should enter in Morcant's house I guess.");
+ close;
+}
+
+OnInit:
+ .distance = 7;
+ .alwaysVisible = true;
+ end;
+}
diff --git a/npc/008-1-1/morcant.txt b/npc/008-1-1/morcant.txt
new file mode 100644
index 00000000..5421c771
--- /dev/null
+++ b/npc/008-1-1/morcant.txt
@@ -0,0 +1,63 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Morcant the Captain, taking care on harbor issues.
+// THIS IS A PLACEHOLDER!
+
+008-1-1,58,57,0 script Morcant NPC_MORCANT,{
+ speech
+ l("Hello."),
+ l("My name is Morcant. I am a Captain, a bit bored since this harbor is not frequented much."),
+// l("I would like to offer you food and tell you stories, but.. have you ever heard of WildX? I won't need to say more, do I?");
+ l("The only floating ship I've seen so far was the one with Legion soldiers sent to scout around."),
+ l("It was my first time that I've met someone from Aemil."),
+ l("I don't like to see armed people lurking around but feel free to stay as long as you wish but don't cause trouble."),
+ next;
+ select
+ l("Not really but okay...?"),
+ l("Actually, I am after your Stew recipe!"),
+ l("Anything to do around these parts?"),
+ l("Can you tell me the directions again?");
+ mes "";
+ switch (@menu)
+ {
+ case 2:
+ mesn;
+ mesq l("Hohoho! That is a family's trade secret!"); // Merry Christmas?
+ if (!getq(General_SmearedHands)) {
+ next;
+ mesn;
+ mesq l("You don't even know how to cook. %s.. Ah, good old times.", any(
+ l("I've learned cooking with Yannika."),
+ l("I had tasty barbecue with Crane.")
+ ));
+ }
+ break;
+ case 3:
+ mesn;
+ mesq l("Hmm, you might want to ask Galimatia, my neighbor.");
+ next;
+ mesn;
+ mesq l("She is always taking care of her bees, though.");
+ break;
+ case 4:
+ mesn;
+ mesq l("There should be a fair number of signposts around. Anyway.");
+ next;
+ mesn;
+ mesq l("Go east to reach Hurnscald. Just follow the road, really.");
+ next;
+ mesn;
+ mesq l("And do not go south. It is haunted.");
+ break;
+ }
+ close;
+
+OnInit:
+OnInstanceInit:
+ .distance = 4;
+ .speed=120;
+ //.alwaysVisible=true;
+ end;
+}
diff --git a/npc/008-1-1/sign.txt b/npc/008-1-1/sign.txt
new file mode 100644
index 00000000..3b22dfa9
--- /dev/null
+++ b/npc/008-1-1/sign.txt
@@ -0,0 +1,22 @@
+// Evol scripts.
+// Authors:
+// Micksha
+// Description:
+// Sign pillars in West Woodland.
+
+008-1-1,53,58,0 script Sign#008-1-1-merchant NPC_NO_SPRITE,{
+ npctalkonce l("Merchant House");
+ close;
+
+OnInit:
+ .distance = 1;
+ end;
+}
+008-1-1,157,87,0 script Sign#008-1-1-central NPC_NO_SPRITE,{
+ npctalkonce l("Right: Hurnscald | Down: Swamp");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/008-1-1/soldiers.txt b/npc/008-1-1/soldiers.txt
new file mode 100644
index 00000000..744635eb
--- /dev/null
+++ b/npc/008-1-1/soldiers.txt
@@ -0,0 +1,31 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Legion Guards serving Hal.
+// THIS IS A PLACEHOLDER!
+
+
+// FIXME We better put some more random answers
+
+008-1-1,62,28,0 script Soldier#1 NPC_RAIJIN_FEMALE_LEGION_ARTIS,{
+ speech
+ l("Hi!"),
+ l("I am not allowed to talk to strangers.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+008-1-1,54,30,0 script Soldier#2 NPC_HUMAN_MALE_LEGION_ARTIS,{
+ speech
+ l("Hi!"),
+ l("I am not allowed to talk to strangers.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1-2/_import.txt b/npc/008-1-2/_import.txt
new file mode 100644
index 00000000..f49fc06e
--- /dev/null
+++ b/npc/008-1-2/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-1-2: Swamp
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-1-2/_warps.txt",
+"npc/008-1-2/sign.txt",
diff --git a/npc/008-1-2/_warps.txt b/npc/008-1-2/_warps.txt
new file mode 100644
index 00000000..c7ee0e45
--- /dev/null
+++ b/npc/008-1-2/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1-2: Swamp warps
+008-1-2,181,31,0 warp #008-1-2_181_31 1,0,008-1-1,180,197
+008-1-2,249,48,0 warp #008-1-2_249_48 0,0,008-1,23,216
diff --git a/npc/008-1-2/sign.txt b/npc/008-1-2/sign.txt
new file mode 100644
index 00000000..587d090e
--- /dev/null
+++ b/npc/008-1-2/sign.txt
@@ -0,0 +1,31 @@
+// Evol scripts.
+// Authors:
+// Micksha
+// Description:
+// Sign pillars in West Woodland.
+
+008-1-2,218,80,0 script Sign#008-1-2-northeast NPC_NO_SPRITE,{
+ npctalkonce l("Up: West Woodland | Right: Dimond's Cove | Left: Sorentown");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1-2,145,80,0 script Sign#008-1-2-sorentown NPC_NO_SPRITE,{
+ npctalkonce l("Left: Asphodel Moor | Right: All directions");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1-2,39,192,0 script Sign#008-1-2-asphodel NPC_NO_SPRITE,{
+ npctalkonce l("Down: Graveyard (under construction) | Up: All directions");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/008-1/4144.txt b/npc/008-1/4144.txt
new file mode 100644
index 00000000..2c0ec327
--- /dev/null
+++ b/npc/008-1/4144.txt
@@ -0,0 +1,90 @@
+// Evol Script
+// Author:
+// Jesusalva
+// WildX
+// Description:
+// Andrei is not an human, according to studies conducted by TMW Team.
+// He seems to be a highly advanced artificial intelligence.
+// The fact that he was never seen contributes to this theory.
+// Other members opinions:
+// “4144 is a bot which sits on Hurnscald.” ~ Sagratha, 2016
+
+008-1,246,105,0 script Andrei NPC_PLAYER,{
+ function sittingBot;
+ function zealiteLore;
+ // TODO: Maybe we should use Karma here? For discussion
+ @is_billygates=(strcharinfo(0) == "WildX");
+ speech
+ l("Hi.");
+ next;
+ do
+ {
+ select
+ l("Hello."),
+ l("Can I sit on you?"),
+ l("What are you doing?");
+ mes "";
+ switch (@menu)
+ {
+ case 1:
+ break;
+ case 2:
+ sittingBot();
+ break;
+ case 3:
+ zealiteLore();
+ break;
+ }
+ } while (@menu != 1);
+
+ close;
+
+ // Sitting Bot
+ function sittingBot
+ {
+ // This is just an easter egg (for now)
+ if (@is_billygates) {
+ speech S_LAST_NEXT,
+ l("Only if everyone agrees. You'll need to do a vote for that."),
+ l("Just kidding.");
+ }
+
+ // Main dialog
+ speech S_LAST_NEXT,
+ l("I don't care, but there might be some adventurers and staff who might care."),
+ l("That's why you should always ask. This is good social etiqutte, you know?"),
+ l("Anyway, I would advise you to sit closer to the Soul Menhir, instead.");
+ return;
+ }
+
+ // Zealite Info
+ function zealiteLore
+ {
+ speech S_LAST_NEXT,
+ l("I am maintaing Hurnscald's Soul Menhir in working conditions."),
+ l("Soul Menhirs are pieces of Zealite Ore, really needed to cast magic around here."),
+ l("They are not like your usual Terra Ore. Zealite is way more magical and powerful."),
+ l("This is why sometimes people try to steal shards from it... Poor fools.");
+ // Note: On TMW-BR, it is possible to "hit" Soul Menhirs for shards, which allow you to
+ // instantly teleport back to savepoint, even if lore-wise that was prohibted.
+ // This reference doesn't means it is actually possible to try that at all here.
+ return;
+ }
+
+// TODO: Replace with a good sprite and dye robes in green
+OnInit:
+ .@npcId = getnpcid(.name$);
+ setunitdata(.@npcId, UDT_HEADTOP, FancyHat); // Wizard Hat
+ setunitdata(.@npcId, UDT_HEADMIDDLE, SilkRobe);
+ setunitdata(.@npcId, UDT_HEADBOTTOM, CottonGloves);
+ setunitdata(.@npcId, UDT_WEAPON, CottonBoots);
+
+ // What is 4144's hair? He is always wearing his wizard hat
+ setunitdata(.@npcId, UDT_HAIRSTYLE, 7);
+ setunitdata(.@npcId, UDT_HAIRCOLOR, rand(1,20));
+ npcsit;
+
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/008-1/_import.txt b/npc/008-1/_import.txt
new file mode 100644
index 00000000..d09f8c88
--- /dev/null
+++ b/npc/008-1/_import.txt
@@ -0,0 +1,29 @@
+// Map 008-1: Hurnscald
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-1/4144.txt",
+"npc/008-1/_mobs.txt",
+"npc/008-1/_warps.txt",
+"npc/008-1/auldsbel.txt",
+"npc/008-1/banu.txt",
+"npc/008-1/blossom.txt",
+"npc/008-1/confused-tree.txt",
+"npc/008-1/crane.txt",
+"npc/008-1/doors.txt",
+"npc/008-1/hinnak.txt",
+"npc/008-1/jack.txt",
+"npc/008-1/mapflags.txt",
+"npc/008-1/marine.txt",
+"npc/008-1/mikhail.txt",
+"npc/008-1/milly.txt",
+"npc/008-1/old-man.txt",
+"npc/008-1/old-woman.txt",
+"npc/008-1/oscar.txt",
+"npc/008-1/rossy.txt",
+"npc/008-1/sabine.txt",
+"npc/008-1/sergeant-ryan.txt",
+"npc/008-1/shop.txt",
+"npc/008-1/sign.txt",
+"npc/008-1/snarfles.txt",
+"npc/008-1/soul-menhir.txt",
+"npc/008-1/voltain.txt",
+"npc/008-1/wateranimation.txt",
diff --git a/npc/008-1/_mobs.txt b/npc/008-1/_mobs.txt
new file mode 100644
index 00000000..4ca22849
--- /dev/null
+++ b/npc/008-1/_mobs.txt
@@ -0,0 +1,124 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1: Hurnscald mobs
+008-1,270,86,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,271,89,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,273,87,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,276,88,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,275,90,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,280,87,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,279,89,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,282,89,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,283,86,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,203,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,198,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,193,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,188,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,183,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,185,72,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,203,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,198,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,193,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,188,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,180,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,185,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,190,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,195,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,198,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,193,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,188,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,183,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,180,80,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,200,80,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,160,97,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,154,95,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,148,97,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,160,101,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,156,105,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,154,99,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,152,101,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,152,105,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,146,99,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,146,103,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,200,120,2,6 monster Mauve Plant 1036,3,1000,20000
+008-1,184,53,2,2 monster Cobalt Plant 1039,2,1000,30000
+008-1,183,143,6,2 monster Alizarin Plant 1037,3,1000,25000
+008-1,169,142,2,2 monster Pink Flower 1034,1,100,10000
+008-1,159,145,2,2 monster Pink Flower 1034,1,100,20000
+008-1,148,150,2,2 monster Pink Flower 1034,1,100,50000
+008-1,85,120,7,9 monster Mouboo 1023,5,30000,60000
+008-1,79,63,11,2 monster Spider 1044,2,4000,8000
+008-1,290,101,5,3 monster Butterfly 1032,3,10000,10000
+008-1,267,127,2,2 monster Butterfly 1032,2,10000,10000
+008-1,235,118,9,9 monster Butterfly 1032,3,10000,10000
+008-1,241,58,5,3 monster Butterfly 1032,3,10000,10000
+008-1,292,165,5,3 monster Butterfly 1032,3,10000,10000
+008-1,207,139,5,3 monster Butterfly 1032,3,10000,10000
+008-1,165,147,5,3 monster Butterfly 1032,3,10000,10000
+008-1,181,213,14,10 monster Log Head 1031,2,5000,30000
+008-1,244,160,31,11 monster Mana Bug 1035,7,10000,10000
+008-1,232,60,17,26 monster Mana Bug 1035,7,10000,10000
+008-1,275,103,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,277,152,2,1 monster Clover Patch 1033,1,10000,30000
+008-1,203,130,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,156,149,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,193,113,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,289,140,6,2 monster Maggot 1026,3,500,10000
+008-1,285,65,6,2 monster Maggot 1026,3,500,10000
+008-1,170,70,6,2 monster Maggot 1026,3,500,10000
+008-1,65,136,6,2 monster Maggot 1026,3,500,10000
+008-1,47,132,11,15 monster Forest Maggot 1028,7,500,2500
+008-1,120,113,16,11 monster Butterfly 1032,3,10000,10000
+008-1,104,183,11,7 monster Log Head 1031,3,5000,30000
+008-1,203,167,9,10 monster Log Head 1031,2,5000,30000
+008-1,66,185,7,11 monster Log Head 1031,2,5000,30000
+008-1,258,68,5,3 monster Pinkie 1030,2,3000,12000
+008-1,257,88,5,3 monster Pinkie 1030,2,3000,12000
+008-1,295,80,4,5 monster Pinkie 1030,3,2000,8000
+008-1,295,62,5,3 monster Pinkie 1030,2,3000,12000
+008-1,279,46,17,7 monster Silkworm 1040,4,3000,6000
+008-1,220,168,17,7 monster Silkworm 1040,2,3000,6000
+008-1,144,160,21,9 monster Silkworm 1040,4,3000,6000
+008-1,68,167,14,9 monster Silkworm 1040,3,3000,6000
+008-1,46,193,16,28 monster Grass Snake 1042,7,3000,12000
+008-1,166,114,14,5 monster Spiky Mushroom 1049,2,3000,6000
+008-1,128,48,4,5 monster Bandit 1063,1,4000,11000
+008-1,186,33,6,7 monster Spiky Mushroom 1049,4,3000,6000
+008-1,84,77,4,2 monster Scorpion 1043,1,6000,12000
+008-1,106,62,7,4 monster Mouboo 1023,1,30000,120000
+008-1,211,65,2,2 monster Pink Flower 1034,1,100,10000
+008-1,213,123,2,2 monster Pink Flower 1034,1,100,10000
+008-1,37,210,3,12 monster Wicked Mushroom 1050,7,3000,12000
+008-1,54,94,14,13 monster Spiky Mushroom 1049,2,3000,6000
+008-1,146,183,36,25 monster Forest Maggot 1028,12,500,2500
+008-1,77,96,7,5 monster Forest Maggot 1028,3,500,2500
+008-1,185,187,21,11 monster Butterfly 1032,3,10000,10000
+008-1,267,68,30,35 monster Squirrel 1041,7,10000,30000
+008-1,178,180,36,30 monster Squirrel 1041,12,10000,30000
+008-1,161,34,6,7 monster Scorpion 1043,2,6000,12000
+008-1,47,98,23,49 monster Butterfly 1032,5,10000,10000
+008-1,140,144,2,6 monster Mauve Plant 1036,3,1000,2000
+008-1,192,147,3,2 monster Gamboge Plant 1038,2,1000,10000
+008-1,197,136,2,5 monster Cobalt Plant 1039,2,1000,30000
+008-1,109,93,14,5 monster Spiky Mushroom 1049,2,3000,6000
+008-1,111,68,8,3 monster Robin Bandit 1064,2,8000,12000
+008-1,126,80,8,3 monster Bandit 1063,2,5500,8000
+008-1,122,44,4,7 monster Robin Bandit 1064,1,3000,8000
+008-1,259,116,31,20 monster Maggot 1026,6,500,10000
+008-1,221,70,8,11 monster Small Frog 1086,3,3000,30000
+008-1,190,166,8,11 monster Small Frog 1086,2,3000,30000
+008-1,88,197,8,26 monster Small Frog 1086,4,3000,30000
+008-1,228,62,15,11 monster Big Frog 1087,1,6000,60000
+008-1,225,162,15,11 monster Big Frog 1087,1,6000,60000
+008-1,88,190,15,11 monster Big Frog 1087,1,6000,60000
+008-1,124,173,20,23 monster Mouboo 1023,5,30000,60000
+008-1,162,42,36,12 monster Butterfly 1032,3,10000,10000
+008-1,186,52,2,0 monster Mauve Plant 1036,1,1000,20000
+008-1,179,25,5,3 monster Pinkie 1030,2,3000,12000
+008-1,228,107,5,12 monster Brotherhood Fighter 1081,2,6000,18000
+008-1,249,143,18,3 monster Brotherhood Fighter 1081,2,12000,18000
+008-1,283,158,7,5 monster Forest Maggot 1028,3,500,2500
+008-1,66,191,17,27 monster Forest Maggot 1028,5,5000,25000
+008-1,55,204,17,8 monster Spider 1044,2,4000,8000
+008-1,73,54,17,12 monster Bluepar 1088,2,12000,36000
+008-1,33,33,11,12 monster Wolvern 1117,2,10000,10000
+008-1,82,162,38,14 monster Wolvern 1117,3,18000,60000
diff --git a/npc/008-1/_warps.txt b/npc/008-1/_warps.txt
new file mode 100644
index 00000000..af0621c9
--- /dev/null
+++ b/npc/008-1/_warps.txt
@@ -0,0 +1,33 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1: Hurnscald warps
+008-1,276,122,0 warp #008-1_276_122 0,0,008-2-0,26,23
+008-1,274,125,0 warp #008-1_274_125 0,0,008-2-0,23,34
+008-1,259,118,0 warp #008-1_259_118 0,0,008-2-1,33,42
+008-1,261,111,0 warp #008-1_261_111 0,0,008-2-1,38,27
+008-1,236,102,0 warp #008-1_236_102 0,0,008-2-2,28,33
+008-1,260,105,0 warp #008-1_260_105 0,0,008-2-6,27,32
+008-1,272,102,0 warp #008-1_272_102 0,0,008-2-7,36,28
+008-1,292,118,0 warp #008-1_292_118 0,0,008-2-8,36,38
+008-1,243,115,0 warp #008-1_243_115 0,0,008-2-9,30,34
+008-1,273,116,0 warp #008-1_273_116 0,0,008-2-10,37,33
+008-1,275,74,0 warp #008-1_275_74 0,0,008-2-16,25,33
+008-1,281,103,0 warp #008-1_281_103 0,0,008-2-12,30,31
+008-1,122,114,0 warp #008-1_122_114 0,0,008-2-22,30,34
+008-1,71,128,0 warp #008-1_71_128 0,0,008-2-23,52,39
+008-1,106,221,0 warp #008-1_106_221 0,0,008-2-24,32,45
+008-1,236,39,0 warp #008-1_236_39 0,0,008-2-17,52,39
+008-1,151,80,0 warp #008-1_151_80 0,0,008-2-15,35,33
+008-1,256,203,0 warp #008-1_256_203 0,0,008-2-20,25,31
+008-1,128,138,0 warp #008-1_128_138 0,0,008-3-1,35,34
+008-1,250,23,0 warp #008-1_250_23 1,0,008-3-4,88,76
+008-1,283,26,0 warp #008-1_283_26 0,0,008-3-3,37,56
+008-1,287,113,0 warp #008-1_287_113 0,0,008-2-8,26,28
+008-1,252,211,0 warp #008-1_252_211 0,0,008-2-21,22,42
+008-1,257,130,0 warp #008-1_257_130 0,0,008-2-28,25,31
+008-1,233,131,0 warp #008-1_233_131 0,0,008-2-29,36,24
+008-1,287,133,0 warp #008-1_287_133 0,0,008-2-30,52,39
+008-1,20,85,0 warp #008-1_20_85 0,1,008-1-1,246,85
+008-1,165,171,0 warp #008-1_165_171 0,0,008-3-2,175,21
+008-1,289,125,0 warp #008-1_289_125 0,0,008-2-31,29,25
+008-1,22,216,0 warp #008-1_22_216 0,0,009-1,248,48
+008-1,109,82,0 warp #008-1_109_82 0,0,008-3-5,92,107
diff --git a/npc/008-1/auldsbel.txt b/npc/008-1/auldsbel.txt
new file mode 100644
index 00000000..316bf604
--- /dev/null
+++ b/npc/008-1/auldsbel.txt
@@ -0,0 +1,53 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Auldsbel the Magician.
+// THIS IS A PLACEHOLDER!
+
+008-1,119,114,0 script Auldsbel NPC_WIZARD,{
+ // Placeholder please remove
+ if (!MASTERBOOK_PAGES)
+ {
+ inventoryplace MasterBook, 1;
+ getitem MasterBook, 1;
+ MASTERBOOK_PAGES=1;
+ mesc l("Auldsbel discretly stuffs a book on your backpack.");
+ next;
+ speech
+ l("Don't tell anyone about this. Once you kill you a boss, you can try to learn the boss skill by using the book."),
+ l("Beware you have a limited number of pages. Do not let the Legion or the Brotherhood find out you have one."),
+ l("And by the way. I know nothing about this book. And I don't know how to get more pages either.");
+ close;
+ }
+ speech
+ l("Hello."),
+ l("Oh, you look more interested in magic.. the brotherhood did forbid most of the interesting paths of magic, but boring baby spells are still allowed.");
+ // Give poor Auldsbel some weak magic D:
+ if (!MAGIC_CLU[EVOL_MONSTER_IDENTIFY]) {
+ mesn;
+ mesq l("May I interest you in an useless skill?");
+ ShowAbizit(true);
+ next;
+ mesc l("Identify Monsters - Unlocks the %s chat command.", "##B/mi##b");
+ mesc l("It will analyse and inform about the monster stats and drops.");
+ mesc l("If multiple monsters have same name, all of them will be listed.");
+ mesc l("Alias: %s", "##B@monsterinfo##b");
+ next;
+ mesn;
+ mesq l("May I interest you in an useless skill?");
+ mesc l("Skill: %s", getskillname(EVOL_MONSTER_IDENTIFY));
+ // FIXME You know that learn_magic has its own prompt, right?
+ if (askyesno() == ASK_YES) {
+ learn_magic(EVOL_MONSTER_IDENTIFY);
+ }
+ } else {
+ mesn;
+ mesq l("If you come back later, I may teach you something. But psst, practising magic is quite dangerous these days.");
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/banu.txt b/npc/008-1/banu.txt
new file mode 100644
index 00000000..05209a2c
--- /dev/null
+++ b/npc/008-1/banu.txt
@@ -0,0 +1,20 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Banu, the old lady.
+// THIS IS A PLACEHOLDER!
+
+008-1,244,88,0 script Banu NPC_OLD_LADY,{
+ speech
+ l("Hello."),
+ l("You don't have a scythe, by chance? I am too old to mew this field all alone."),
+ l("I asked Hinnak, but he wants at least a beer in exchange for his scythe."),
+ l("But I hate alcohol, so thats not an option for me.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/blossom.txt b/npc/008-1/blossom.txt
new file mode 100644
index 00000000..57782b20
--- /dev/null
+++ b/npc/008-1/blossom.txt
@@ -0,0 +1,77 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Blossom the flower-seller girl.
+// THIS IS A PLACEHOLDER!
+
+008-1,198,138,0 script Blossom NPC_BLOSSOM,{
+ speech
+ l("Hi, my name is Blossom."),
+ l("Strange, it seems I became younger lately."),
+ l("Are you in need of some flowers?");
+
+ do
+ {
+ select
+ l("I love flowers! What do you have for sale?"),
+ l("Not now, thank you."),
+ l("Dont you know something about fertility? I heard rumors."),
+ l("Do you sell Flower Seeds?");
+
+ mes "";
+ switch (@menu)
+ {
+ case 1:
+ closeclientdialog;
+ shop "#Invisible008-1";
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("Oh, ok. Come back later if you need something.");
+ close;
+ case 3:
+ /*
+ speech S_FIRST_BLANK_LINE,
+ l("I heard something too. A girl named Galimatia seems to need help. If only those lazy developers could tell her what she needs.");
+ */
+ mesn;
+ mesq l("I heard something too. A girl named Galimatia seems to need help.");
+ next;
+ mesn;
+ mesq l("But I believe Oscar gave her a fertility recipe...?");
+ next;
+ mesn;
+ mesq l("...Oops, I'm not supposed to say that. Oscar is... Well... Either a genius or a madman, I can't say.");
+ break;
+ case 4:
+ mesn;
+ mesq l("No I don't, but I can exchange them. 3 %s for a %s.", getitemlink(GrassSeeds), getitemlink(FlowerSeeds));
+ next;
+ /*
+ // TODO: Add Andra
+ mesn;
+ mesq l("If you need the opposite, look for Andra.");
+ */
+ if (countitem(GrassSeeds) < 3)
+ break;
+
+ mesc l("Trade with %s?", .name$);
+ if (askyesno() == ASK_YES) {
+ inventoryplace FlowerSeeds, 1;
+ delitem GrassSeeds, 3;
+ getitem FlowerSeeds, 1;
+ mesn;
+ mesq l("Thanks for the trade.");
+ next;
+ }
+ break;
+ }
+ } while (true);
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/confused-tree.txt b/npc/008-1/confused-tree.txt
new file mode 100644
index 00000000..aead40ed
--- /dev/null
+++ b/npc/008-1/confused-tree.txt
@@ -0,0 +1,972 @@
+// Evol scripts.
+// Author:
+// gumi
+// Based on CrazyTree, originally made by:
+// gumi
+// pclouds
+// veryape
+// wushin
+// Description:
+// emulated confused tree prototype
+
+// ~t lowercase hot word regex
+
+008-1,255,109,0 script Confused Tree NPC_CONFUSED_TREE,14,14,{
+
+ function tree_panel {
+ if (is_trusted() == false && #Tree_Trusted == false)
+ {
+ narrator(l("You see a tree."));
+ if (getq(HurnscaldQuests_Inspector) == 2)
+ {
+ select(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ narrator(S_FIRST_BLANK_LINE,
+ l("..."),
+ l("It doesn't reply."));
+ }
+ close;
+ }
+
+ function clear_db {
+ clear();
+ mes(l("##BWARNING:##b you are about to permanently empty the quote database."));
+ next();
+ mes(l("Do you want to continue?"));
+
+ select(
+ l("Abort!"),
+ l("Empty the quote DB"));
+
+ if (@menu == 2)
+ {
+ .@sentence$ = "I am an idiot";
+ mes(l("Please write the following sentence:"));
+ mes("");
+ mesf(" ##B%s.", .@sentence$);
+ input(.@confirm$);
+
+ if (!startswith(strtoupper(.@confirm$), strtoupper(.@sentence$))) {
+ mes(l("Invalid!"));
+ close;
+ }
+
+ query_sql("TRUNCATE TABLE tree_quotes;");
+ mes(l("Database erased."));
+ next();
+ }
+
+ return;
+ }
+
+ function list_commands {
+ clear();
+ mes(l("To grab a quote:"));
+ mes(col(" ~grab ##Bplayer name##b", 7));
+ next();
+ mes(l("To get a quote:"));
+ mes(col(" ~quote anyone", 7));
+ mes(col(" ~quote ##Bplayer name##b", 7));
+ mes(col(" ~quote ##B#number##b", 7));
+ next();
+ mes(l("To remove a quote:"));
+ mes(col(" ~remove quote ##B#number##b", 7));
+ mes(col(" ~remove last quote", 7));
+ next();
+ mes(l("Last seen:"));
+ mes(col(" ~seen ##Bplayer name##b", 7));
+ next();
+ mes(l("To ignore a player:"));
+ mes(col(" ~ignore ##Bplayer name##b", 7));
+ next();
+ mes(l("To unignore a player:"));
+ mes(col(" ~unignore ##Bplayer name##b", 7));
+ next();
+
+ if (is_admin())
+ {
+ mes(l("To trust a player:"));
+ mes(col(" ~trust ##Bplayer name##b", 7));
+ next();
+ mes(l("To de-trust a player:"));
+ mes(col(" ~untrust ##Bplayer name##b", 7));
+ next();
+ }
+ return;
+ }
+
+ do
+ {
+ clear();
+ setnpcdialogtitle(l("Tree Control Panel"));
+ mes(l("Oh noes! You found my secret backdoor!"));
+ next();
+ mes(l("Please select an option:"));
+
+ select(
+ l("List the commands"),
+ rif(is_admin(), l("Empty the quote DB")),
+ l("Dance for me"));
+
+ switch (@menu)
+ {
+ case 1: list_commands(); break;
+ case 2: clear_db(); break;
+ default: speech(l("Too lazy.")); close;
+ }
+
+ } while (true);
+
+ end;
+ }
+
+ // utility functions below
+
+ function check_is_ignored {
+ .@val = htget(.ignore_ht, strcharinfo(PC_NAME), 0);
+
+ if (.@val > gettimetick(2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ else if (.@val > 0)
+ {
+ htput(.ignore_ht, strcharinfo(PC_NAME), 0); // remove expired entries
+ }
+
+ return;
+ }
+
+ function special_name {
+ .@name$ = strcharinfo(PC_NAME);
+ .@low$ = strtolower(.@name$);
+
+ if (rand(.sname_rate) == 0)
+ {
+ for (.@i = 0; .@i < .alias; .@i += 2)
+ {
+ if (.@low$ ~= .alias$[.@i])
+ {
+ explode(.@aliases$, .alias$[.@i+1], "`");
+ .@name$ = .@aliases$[rand(getarraysize(.@aliases$))];
+ break;
+ }
+ }
+ }
+
+ return .@name$;
+ }
+
+ function face {
+ if (gettimetick(2) - .last_emote < .emote_rate)
+ {
+ ++.ignored_times;
+ return;
+ }
+
+ .last_emote = gettimetick(2);
+ return emotion(getarg(0, E_SURPRISE));
+ }
+
+ function rp {
+ // used for queries
+ return replacestr(getarg(0,""), "~t", strtolower("(?:" + .name$ + "|" + .hotwords$ + ")"));
+ }
+
+ function format_reply {
+ // used for replies
+ .@str$ = getarg(0, "");
+
+ // search for {{mustaches}}
+ while (.@str$ ~= "{{([^}]+)}}")
+ {
+ .@sub$ = replacestr($@regexmatch$[1], " ", ""); // remove whitespaces
+ .@sub$ = strtolower(.@sub$); // always lowercase the var name
+ .@capitalize = .@titlecase = .@allcaps = false;
+
+ if (charat(.@sub$, 0) == "^")
+ {
+ .@capitalize = true;
+ .@sub$ = substr(.@sub$, 1, getstrlen(.@sub$) - 1); // strip first char
+ }
+
+ else if (charat(.@sub$, 0) == "+")
+ {
+ .@titlecase = true;
+ .@sub$ = substr(.@sub$, 1, getstrlen(.@sub$) - 1); // strip first char
+ }
+
+ else if (charat(.@sub$, 0) == "!")
+ {
+ .@allcaps = true;
+ .@sub$ = substr(.@sub$, 1, getstrlen(.@sub$) - 1); // strip first char
+ }
+
+ if (compare(.@sub$, ",")) {
+ .@var$ = sprintf(".H%s$", substr(md5(.@sub$), 0, 25));
+
+ if (getelementofarray(getd(.@var$), 1) == "") {
+ explode(.@sub2$, .@sub$, ",");
+ .@size = 1;
+
+ for (.@i = 0; .@i < getarraysize(.@sub2$); ++.@i) {
+ .@subsize = getd(sprintf(".D_%s", .@sub2$));
+ copyarray(getelementofarray(getd(.@var$), .@size), getd(sprintf(".D_%s$[1]", .@sub2$)), .@subsize);
+ .@size += .@subsize;
+ }
+ }
+ } else {
+ .@var$ = sprintf(".D_%s$", .@sub$);
+ }
+
+ .@rep$ = relative_array_random(getd(.@var$));
+
+ if (.@capitalize) .@rep$ = capitalize(.@rep$);
+ else if (.@titlecase) .@rep$ = titlecase(.@rep$);
+ else if (.@allcaps) .@rep$ = strtoupper(.@rep$);
+
+ .@str$ = replacestr(.@str$, $@regexmatch$[0], .@rep$); // remove the mustache, replace by value
+ }
+
+ // search for emotes
+ if (.@str$ ~= "%%([^ ])")
+ {
+ // only handling a few of them
+ switch (ord($@regexmatch$[1]))
+ {
+ case 73: face(any(E_WINK, E_ANGEL)); break;
+ case 83: face(any(E_SAD, E_CRYING)); break;
+ case 85: face(E_SURPRISE); break;
+ case 93: face(any(E_HEARTEYE, E_HEART)); break;
+ case 94: face(E_DISGUST); break;
+ case 99: face(E_DEAD); break;
+ case 105: face(E_CRYING); break;
+ case 106:
+ case 91: face(any(E_SPEECH, E_BLAH)); break;
+ case 107: face(E_INSULTBUBBLE); break;
+ default: .@unhandled = true;
+ }
+
+ if (.@unhandled != true)
+ {
+ if (.@str$ == $@regexmatch$[0]) end; // don't send handled, emote-only messages
+ .@str$ = replacestr(.@str$, " "+ $@regexmatch$[0], ""); // otherwise strip the emote
+ }
+ }
+
+ // built-in variables
+ .@str$ = replacestr(.@str$, "~n", .name$); // npc name
+ .@str$ = replacestr(.@str$, "~p", special_name()); // player name or special name
+ .@str$ = replacestr(.@str$, "~P", strcharinfo(PC_NAME)); // unaltered player name
+
+ return rp(.@str$);
+ }
+
+ function strip_colors {
+ .@str$ = replacestr(getarg(0, ""), "##0", "");
+ .@str$ = replacestr(.@str$, "##1", "");
+ .@str$ = replacestr(.@str$, "##2", "");
+ .@str$ = replacestr(.@str$, "##3", "");
+ .@str$ = replacestr(.@str$, "##4", "");
+ .@str$ = replacestr(.@str$, "##5", "");
+ .@str$ = replacestr(.@str$, "##6", "");
+ .@str$ = replacestr(.@str$, "##7", "");
+ .@str$ = replacestr(.@str$, "##8", "");
+ .@str$ = replacestr(.@str$, "##9", "");
+ return replacestr(.@str$, "##a", "");
+ }
+
+ function strip_formatting {
+ .@str$ = strip_colors(getarg(0, ""));
+ .@str$ = replacestr(.@str$, "##B", "");
+ return replacestr(.@str$, "##b", "");
+ }
+
+ function delayed_reply {
+ ++.answered_times;
+ @tree_reply$ = getarg(0, "");
+ addtimer(.delay_reply, .name$ + "::OnDoReply");
+ return;
+ }
+
+ function reply {
+ .@reply$ = format_reply(getarg(0, ""));
+ getmapxy(.@pc_map$, .@pc_x, .@pc_y, UNITTYPE_PC); // get char location
+
+ if (((.@reply$ == .last_reply$ && gettimetick(2) - .last_reply < .repeat_rate)
+ || gettimetick(2) - .last_reply < .talk_rate
+ || (gettimetick(2) - .blocked < .block_time && is_trusted() == false)
+ || .@pc_map$ != .map$
+ || distance(.x, .y, .@pc_x, .@pc_y) > .distance
+ || .@reply$ == "")
+ && is_dev() == false)
+ {
+ ++.ignored_times;
+ return;
+ }
+
+ .last_reply = gettimetick(2);
+ .last_reply$= .@reply$;
+
+ delayed_reply(.@reply$);
+ return;
+ }
+
+ function seen_me {
+ if (playerattached() > 0 && htexists(.seen_ht))
+ {
+ htput(.seen_ht, strcharinfo(PC_NAME), gettimetick(2));
+ }
+ return;
+ }
+
+ function have_you_seen {
+ .@player$ = getarg(0, "");
+ .@player = getcharid(CHAR_ID_ACCOUNT, .@player$);
+
+ if (.@player > 0)
+ {
+ // nested if, because they don't short-circuit
+ if (checkoption(Option_Invisible, .@player) == false) {
+ delayed_reply(sprintf("Player `%s` is currently online.", .@player$));
+ end;
+ }
+ }
+
+ .@time = htget(.seen_ht, .@player$, 0);
+
+ if (.@time < 1)
+ delayed_reply(sprintf("I haven't seen player `%s` today.", .@player$));
+
+ else
+ delayed_reply(sprintf("Player `%s` was last seen %s.", .@player$, FuzzyTime(.@time, 0, 99)));
+
+ end;
+ }
+
+ function special_drops {
+ .@drop$ = relative_array_random(.drops$);
+ .@name$ = strcharinfo(PC_NAME);
+ .@low$ = strtolower(.@name$);
+
+ if (rand(.sdrop_rate) == 0)
+ {
+ for (.@i = 0; .@i < .sdrops; .@i += 2)
+ {
+ if (.@low$ ~= .sdrops$[.@i])
+ {
+ explode(.@d$, .sdrops$[.@i+1], "`");
+ .@drop$ = .@d$[rand(getarraysize(.@d$))];
+ break;
+ }
+ }
+ }
+
+ return .@drop$;
+ }
+
+ function roll_dice {
+ .@dices = max(min(getarg(0, 1), 8), 1); // 1..8
+ .@sides = max((getarg(1, 6) < 1 ? 6 : getarg(1, 6)), 1); // 1..MAX_INT
+
+ .@result$ = sprintf("*rolls the dice%s: %d",
+ rif(.@dices > 1, "s"), rand(1, .@sides)); // first dice
+
+ for (.@d = 1; .@d < .@dices; ++.@d)
+ {
+ .@result$ += ", " + rand(1, .@sides);
+ }
+
+ return .@result$ + ".*";
+ }
+
+ function flip_coin {
+ .@coins = getarg(0, 1);
+
+ .@result$ = sprintf("*flips the coin%s: %s",
+ rif(.@coins > 1, "s"), (rand(2) == 1 ? "heads" : "tails")); // first coin
+
+ for (.@c = 1; .@c < .@coins; ++.@c)
+ {
+ .@result$ += ", " + (rand(2) == 1 ? "heads" : "tails");
+ }
+
+ return .@result$ + ".*";
+ }
+
+ function roulette {
+ if (.roulette == 1)
+ {
+ npctalk("*pulls the trigger: *##BBANG##b*.*");
+ delayed_reply("*reloads and spins the chambers.*");
+ .roulette = rand(1, 7); // the Nagant_M1895 has 7 chambers
+
+ // now the fun part
+ nude();
+ percentheal(-100, 0);
+ }
+
+ else
+ {
+ delayed_reply("*pulls the trigger: *click*.*");
+ .roulette = (.roulette == 7 ? 1 : .roulette + 1);
+ }
+
+ end;
+ }
+
+ function monologue_player {
+ return sprintf("Your current monologue is at least %d line%s long.",
+ @monologue, rif(@monologue != 1, "s"));
+ }
+
+ function who_player {
+ return sprintf("You seem to be ##B~P##b [%i:%i].",
+ getcharid(CHAR_ID_ACCOUNT), getcharid(CHAR_ID_CHAR));
+ }
+
+ function make_quote_table {
+ // Do not modify this
+ query_sql("CREATE TABLE IF NOT EXISTS `tree_quotes` ("
+ " `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,"
+ " `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',"
+ " `grabber` INT(11) UNSIGNED NOT NULL DEFAULT '0',"
+ " `timestamp` INT(10) UNSIGNED NOT NULL DEFAULT '0',"
+ " `message` VARCHAR(150) NOT NULL DEFAULT '',"
+ " PRIMARY KEY (`id`),"
+ " KEY `char_id` (`char_id`),"
+ " KEY `grabber` (`grabber`)"
+ ") ENGINE=MyISAM;");
+
+ .last_query = gettimetick(2);
+ return;
+ }
+
+ function grab_quote {
+ .@name$ = getarg(0, "");
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ if (.@name$ == strcharinfo(PC_NAME))
+ {
+ delayed_reply("##BError: You may not grab yourself.");
+ end;
+ }
+
+ explode(.@tmp$[0], htget(.msg_ht, .@name$, ""), ":"); // get last message, if any
+ htput(.msg_ht, .@name$, ""); // ensure you can't grab twice the same message
+
+ .@char_id = atoi(.@tmp$[0]); // grab the char id part
+
+ if (.@char_id < 1)
+ {
+ delayed_reply(sprintf("##BError: I couldn't find anything to grab from player `%s`.", .@name$));
+ end;
+ }
+
+ .@msg$ = implode(.@tmp$, ":"); // put it back together
+ .@start = getstrlen(.@tmp$[0]) + getstrlen(.@tmp$[1]) + 2; // char:time:msg <= we just want the msg part
+ .@msg$ = escape_sql(strip_formatting(substr(.@msg$, .@start, getstrlen(.@msg$) - 1))); // sanitize
+
+ if (.@msg$ == "")
+ {
+ delayed_reply("##BError: Message is empty or malformed. It cannot be grabbed.");
+ end;
+ }
+
+ else if (.@msg$ ~= "^[!#~@]?(?:grab)?shield(?:ed)?(?:[:.!]? .*)?$")
+ {
+ delayed_reply("##BError: Message is shielded.");
+ end;
+ }
+
+ query_sql(sprintf("INSERT INTO tree_quotes (char_id,grabber,timestamp,message) VALUES (%i,%i,%i,'%s');",
+ .@char_id, getcharid(CHAR_ID_CHAR), gettimetick(2), .@msg$));
+
+ query_sql("SELECT MAX(id) FROM tree_quotes;", .q_last_id); // get the last quote id
+
+ .last_query = gettimetick(2);
+
+ delayed_reply(sprintf("Success: Quote grabbed. (#%i)", .q_last_id));
+ end;
+ }
+
+ function remove_quote {
+ .@tmp = getarg(0, 0);
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ query_sql(sprintf("SELECT id FROM tree_quotes WHERE id = %i ORDER BY id DESC LIMIT 1;", .@tmp), .@id); // check if it exists
+
+ if (.@id < 1)
+ {
+ delayed_reply(sprintf("##BError: I couldn't find quote #%i in the database.", .@tmp));
+ end;
+ }
+
+ query_sql(sprintf("DELETE FROM tree_quotes WHERE id = %i ORDER BY id DESC LIMIT 1;", .@id));
+
+ .last_query = gettimetick(2);
+
+ delayed_reply(sprintf("Success: Quote removed. (#%i)", .@id));
+ end;
+ }
+
+ function cite_quote {
+ .@id = getarg(0,0);
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ query_sql(sprintf("SELECT t.id, c.name AS grabee, d.name AS grabber, t.timestamp, t.message "
+ "FROM `tree_quotes` t "
+ "JOIN `char` c ON t.char_id = c.char_id "
+ "JOIN `char` d ON t.grabber = d.char_id "
+ "WHERE t.id=%i ORDER BY t.id DESC LIMIT 1;",
+ .@id),
+ .@nid[0], .@grabee$[0], .@grabber$[0], .@time[0], .@msg$[0]);
+
+ .last_query = gettimetick(2);
+
+ if (.@nid[0] < 1)
+ {
+ delayed_reply(sprintf("##BError: I couldn't find quote #%i in the database.", .@id));
+ end;
+ }
+
+ delayed_reply(sprintf("<%s> ##B%s##b ##a— grabbed by %s %s.",
+ .@grabee$[0], .@msg$[0], .@grabber$[0], FuzzyTime(.@time[0],0,1)));
+ end;
+ }
+
+ function random_quote {
+ .@name$ = escape_sql(getarg(0, ""));
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ query_sql("SELECT t.id, c.name AS grabee, d.name AS grabber, t.timestamp, t.message "
+ "FROM `char` c "
+ "JOIN `tree_quotes` t ON t.char_id = c.char_id "
+ "JOIN `char` d ON d.char_id = t.grabber " +
+ rif(.@name$ != "", sprintf("WHERE c.name='%s' ", .@name$)) +
+ "ORDER BY RAND() LIMIT 1;",
+ .@nid[0], .@grabee$[0], .@grabber$[0], .@time[0], .@msg$[0]);
+
+ .last_query = gettimetick(2);
+
+ if (.@nid[0] < 1)
+ {
+ if (.@name$ != "")
+ delayed_reply(sprintf("##BError: I couldn't find any quote from `%s` in the database.", getarg(0, "")));
+ else
+ delayed_reply("##BError: The quote database is empty.");
+ end;
+ }
+
+ delayed_reply(sprintf("<%s> ##B%s##b ##a— grabbed by %s %s. (#%i)",
+ .@grabee$[0], .@msg$[0], .@grabber$[0], FuzzyTime(.@time[0],0,1), .@nid[0]));
+ end;
+ }
+
+ function trigger_hotword {
+ .@o$ = getarg(0, ""); // original lowercase
+ .@m$ = replacestr(.@o$, "*", ""); // original lowercase clean
+
+
+ if (.@m$ ~= "(?:^| )tell(?: (?:me|him|her|us|them))? a(?:n ?other| lame| bad| boring)? joke")
+ reply(relative_array_random(.jokes$));
+
+ else if (.@m$ ~= "(?:^| )heal me(?:$|[^a-z])")
+ reply(relative_array_random(.healing$));
+ // XXX: maybe actually heal the player once in a while
+
+ else if (.@m$ ~= "(?:^| )(?:what|who) are you")
+ reply(relative_array_random(.whoami$));
+
+ else if (.@m$ ~= rp("(?:^| )(?:hi+|hello|heya?|hiya|good (?:morning|afternoon))[^a-z]* .*~t|~t.* (?:hi+|hello|heya?|hiya)"))
+ {
+ .blocked = 0;
+ .@rpl$ = relative_array_random(.greetings$);
+ reply(.@rpl$);
+ }
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:kicks?|shakes?) .*~t"))
+ reply(special_drops());
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:cuts?|nukes?|kills?|chops? down|saws?|hews?|murders?) .*~t"))
+ reply(relative_array_random(.kill$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )pokes? .*~t"))
+ reply(relative_array_random(.poke$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:waters?|pees?|licks?) .*~t"))
+ reply(relative_array_random(.disgusting$));
+
+ else if (compare(.@m$, " answer ") && .@m$ ~= "(?:life|universe|everything)(?:$|[^a-z])")
+ reply(relative_array_random(.answer$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:burns?|incinerates?|ignites?) .*~t"))
+ reply(relative_array_random(.burning$));
+ // XXX: maybe here send a fire particle effect
+
+ else if (.@m$ ~= rp("(?:^| )die ~t"))
+ reply(relative_array_random(.die$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )bites? .*~t|(?:^[*]| )drops? .* on ~t"))
+ reply(relative_array_random(.silly$));
+
+ else if (.@m$ ~= rp("(?:^| )(?:loves?|hugs?|kiss(es)?) .*~t|~t.* love(?:$|[^a-z])"))
+ reply(relative_array_random(.love$));
+
+ else if (.@m$ ~= rp("(?:^| )dance .*~t|~t.* dance(?:$|[^a-z])"))
+ reply(relative_array_random(.dance$));
+
+ else if (.@m$ ~= rp("(?:^| )hates? .*~t"))
+ reply(relative_array_random(.hate$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:eats?|shoots?|plucks?|tortures?|slaps?|slaps?|poisons?|breaks?|stabs?|throws?|punch(?:es)?) .*~t"))
+ reply(relative_array_random(.pain$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:climbs?|rides?|mounts?) .*~t"))
+ reply(relative_array_random(.climb$));
+
+ else if (.@m$ ~= "(?:^| )(?:see y(?:a|ou)|good night|(?:bye)?bye+)(?:$|[^a-z])")
+ reply(relative_array_random(.bye$));
+
+ else if (.@m$ ~= rp("(?:^| )bad ~t"))
+ reply(relative_array_random(.bad$));
+
+ else if (.@m$ ~= "(?:^| )(?:how old are you|uptime)(?:$|[^a-z])")
+ reply("%%B Server uptime: " + FuzzyTime(.uptime, 1, 99) + ".");
+
+ else if (.@m$ ~= "(?:^| )how chatty are you(?:$|[^a-z])")
+ reply("%%B Answered " + .answered_times + " times, ignored " + .ignored_times + " times.");
+
+ else if (.@m$ ~= "(?:^| )what.* version(?:$|[^a-z])")
+ reply("%%B ~n, version " + .version + "."); // XXX: maybe return Hercules version and serverdata commit instead
+
+ else if (.@m$ ~= "(?:^| )(?:(?:8|eight)[ -]?ball|(?:should|would|will|do|does) (?:i|you|he|she|it|we|they))(?:$|[^a-z])")
+ reply(relative_array_random(.eightball$));
+
+ else if (.@m$ ~= "(?:^| )roll(?: a| the)? dice(?:$|[^a-z])")
+ reply(roll_dice(1, 6));
+
+ else if (.@m$ ~= "(?:^| )roll(?: a)? ([1-8])d((?:[1-9][0-9]{0,10})?)(?:$|[^0-9a-z])")
+ reply(roll_dice(atoi($@regexmatch$[1]), atoi($@regexmatch$[2])));
+
+ else if (.@m$ ~= "(?:^| )roll ([1-8]) dices?(?:$|[^a-z])")
+ reply(roll_dice(atoi($@regexmatch$[1]), 6));
+
+ else if (.@m$ ~= "(?:^| )(?:flip|toss)(?: a| the)? coin(?:$|[^a-z])")
+ reply(flip_coin(1));
+
+ else if (.@m$ ~= "(?:^| )(?:flip|toss) ([1-8]) coins?(?:$|[^a-z])")
+ reply(flip_coin(atoi($@regexmatch$[1])));
+
+ else if (.@m$ ~= "(?:^| )(?:press|pull)(?: the)? trigger(?:$|[^a-z])")
+ roulette();
+
+ else if (.@m$ ~= "(?:^| )(?:how long|what) is(?: my)? monologue(?:$|[^a-z])")
+ reply(monologue_player());
+
+ else if (.@m$ ~= "(?:^| )who am i(?:$|[^a-z])")
+ reply(who_player());
+
+ else if (.@m$ ~= "(?:^| )shut up(?:$|[^a-z])")
+ {
+ reply(relative_array_random(.shut_up$));
+ .blocked = gettimetick(2);
+ }
+
+ else if (rand(.dunno_rate) == 0)
+ reply(relative_array_random(.no_idea$));
+
+ else
+ ++.ignored_times;
+
+ end;
+ }
+
+ function trigger_hiall {
+ if (rand(.hiall_rate) == 0)
+ reply(relative_array_random(.greetings$));
+
+ else
+ ++.ignored_times;
+
+ end;
+ }
+
+OnClick:
+ tree_panel();
+ end;
+
+
+OnTalkNearby:
+ .@no_nick$ = strip(strip_formatting(substr($@p0$, getstrlen(strcharinfo(PC_NAME)) + 3, getstrlen($@p0$) - 1))); // not very obvious stuff
+ .@no_nick_lower$ = strtolower(.@no_nick$); // FIXME: hercules doesn't have a way to do case insensitive regex yet
+ .@no_nick_clean$ = replacestr(.@no_nick_lower$, "*", "");
+
+ htput(.msg_ht, strcharinfo(PC_NAME), getcharid(CHAR_ID_CHAR) + ":" + gettimetick(2) + ":" + .@no_nick$); // log last message, for quotegrabs
+ .lastsender = getcharid(CHAR_ID_CHAR); // for monologue
+
+ .last_activity = gettimetick(2); // for the auto-janitor
+
+ if ((is_trusted() || #Tree_Trusted) && charat(.@no_nick$, 0) == .symbol$)
+ {
+ if (.@no_nick$ ~= "^.grab \"?([^#:@\"]{4,23})\"?$")
+ reply(grab_quote($@regexmatch$[1]));
+
+ else if (.@no_nick$ ~= "^.(?:ungrab|remove|delete)(?: quote)? #([0-9]+)$")
+ reply(remove_quote(atoi($@regexmatch$[1])));
+
+ else if (.@no_nick$ ~= "^.(?:ungrab|remove|delete)(?: last(?: quote)?)?$")
+ reply(remove_quote(.q_last_id));
+
+ else if (.@no_nick$ ~= "^.(?:quote|cite) #([0-9]+)$")
+ reply(cite_quote(atoi($@regexmatch$[1])));
+
+ else if (.@no_nick$ ~= "^.(?:(?:random )?quote|cite)(?: anyone| someone| random)?$")
+ reply(random_quote());
+
+ else if (.@no_nick$ ~= "^.(?:quote|cite) \"?([^#:@\"]{4,23})\"?$")
+ reply(random_quote($@regexmatch$[1]));
+
+ else if (.@no_nick$ ~= "^.seen \"?([^#:@\"]{4,23})\"?$")
+ reply(have_you_seen($@regexmatch$[1]));
+
+ // to allow trusted testers to reboot without knowing the exit code
+ else if (debug && .@no_nick$ ~= "^.re(?:boot|load|start)(?:(?: the)? server)?$")
+ {
+ announce("The server is rebooting. This may take a couple minutes.", bc_all);
+ sleep2(1000);
+ atcommand("@serverexit 104");
+ }
+
+ // exit, pull all, clean, build, reboot
+ else if (debug && .@no_nick$ ~= "^.re-?build(?:(?: the)? server)?$")
+ {
+ announce("The server is rebuilding. This will take several minutes.", bc_all);
+ sleep2(1000);
+ atcommand("@serverexit 108");
+ }
+
+ else if (.@no_nick$ ~= "^.(?:add )?ignored? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ htput(.ignore_ht, strcharinfo(PC_NAME, .@chr), gettimetick(2) + 3600);
+ reply(sprintf("Success: Player `%s` is now ignored for 1 hour.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else if (.@no_nick$ ~= "^.(?:un|de-?|remove )ignored? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ htput(.ignore_ht, strcharinfo(PC_NAME, .@chr), 0);
+ reply(sprintf("Success: Player `%s` is no longer ignored.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else if (is_admin() && .@no_nick$ ~= "^.(?:add )?trust(?:ed)? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ set(getvariableofpc(#Tree_Trusted, .@chr), true);
+ reply(sprintf("Success: Player `%s` can now use restricted commands.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else if (is_admin() && .@no_nick$ ~= "^.(?:un|de-?|remove )trust(?:ed)? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ set(getvariableofpc(#Tree_Trusted, .@chr), false);
+ reply(sprintf("Success: Player `%s` can no longer use restricted commands.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else
+ reply("##BError: Command not found or invalid syntax.");
+ }
+
+ else if (.@no_nick_lower$ ~= rp("^(~t[^a-z ]* .*|(?:.* (?:~t[^a-z ]* .*|~t[^ a-z]*)))$"))
+ {
+ check_is_ignored();
+ trigger_hotword($@regexmatch$[1]);
+ }
+
+ else if (.@no_nick_clean$ ~= "^(hi(ya)?|hello|heya?) (all|friends|every(one|body))")
+ {
+ check_is_ignored();
+ trigger_hiall();
+ }
+
+ else
+ {
+ if (.lastsender == getcharid(CHAR_ID_CHAR))
+ @monologue++;
+
+ else
+ @monologue = 1;
+ }
+
+ // TODO: eliza mode, whisper eliza mode
+ end;
+
+OnTouch:
+ if (rand(.touch_rate) == 0) {
+ face();
+ }
+ end;
+
+OnDoReply:
+ if (@tree_reply$ != "") {
+ npctalk(@tree_reply$);
+ @tree_reply$ = "";
+ }
+ end;
+
+OnPCLogoutEvent:
+ seen_me();
+ end;
+
+OnTimer3600000:
+ // scheduled janitor
+ .@now = gettimetick(2);
+ initnpctimer(); // schedule next
+
+ if (.last_activity > (.@now - 3600)) {
+ end; // last activity is too recent
+ }
+
+ // cleanup routine below
+ .lastsender = 0;
+ .last_activity = 0;
+ .last_reply = 0;
+ .last_emote = 0;
+ .last_query = 0;
+ .blocked = 0;
+ .enable_janitor = 0;
+
+ htclear(.msg_ht); // empty the message table (quotegrabs)
+ htclear(.ignore_ht); // empty the ignore table
+
+ .@it = htiterator(.seen_ht); // allocate new iterator
+ for (.@key$ = htinextkey(.@it); hticheck(.@it); .@key$ = htinextkey(.@it)) {
+ if (.@key$ == "") {
+ continue;
+ }
+
+ if (htget(.seen_ht, .@key$, 0) < (.@now - 86400)) {
+ htput(.seen_ht, .@key$, 0); // remove from hash table if older than 24h
+ }
+ }
+ htidelete(.@it); // free the iterator
+
+ face(); // do an emote (because why not)
+ end;
+
+
+OnDay0320:
+ .dir = DOWNLEFT;
+ end;
+
+
+OnDay0621:
+ .dir = LEFT;
+ end;
+
+
+OnDay0922:
+ .dir = UPLEFT;
+ end;
+
+
+OnDay1221:
+ .dir = DOWN;
+ end;
+
+
+OnInit:
+ // config below
+ .hotwords$ = "tree"; // what hot words the npc should listen to, besides its own name (regex)
+ .distance = 14; // the npc will only listen to player within X tiles
+ .dir = season_direction(); // sprite direction according to the season
+ .talk_rate = 1; // min number of seconds to wait between replies
+ .repeat_rate = 1; // min number of seconds to wait before sending the same message twice in a row
+ .block_time = 600; // how long to stay quiet after someone says shut up, in seconds
+ .emote_rate = 3; // min number of seconds to wait between emotes
+ .sdrop_rate = 8; // 1 in X chances to get a special drop
+ .sname_rate = 8; // 1 in X chances to get a special name
+ .dunno_rate = 2; // 1 in X chances to get a reply when the command is not found
+ .hiall_rate = 2; // 1 in X chances to reply to a "hi everyone"
+ .touch_rate = 4; // 1 in X chances to trigger the OnTouch action
+ .qpoll_rate = 1; // min number of seconds to wait before calling the sql db again for GMs
+ .qpoll_rate2 = 5; // min number of seconds to wait before calling the sql db again for non-GMs (currently unused)
+ .delay_reply = 250; // number of ms to wait to reply
+ .enable_janitor = true; // automatically free memory when idle
+ .symbol$ = "~"; // symbol for GM-only commands
+
+ // register some arrays
+ callfunc("TREE_dictionaries");
+
+ // do random stuff
+ make_quote_table();
+ face();
+
+ // boring stuff below
+ .version[0] = 21; // increase this when you make a change
+ .version[1] = 1;
+ .uptime = gettimetick(2);
+ .alwaysVisible = true; // the NPC doesn't de-spawn when moving away
+ .pid = 1; // regex pattern id
+ .msg_ht = htnew(); // hashtable id for message history
+ .seen_ht = htnew(); // hashtable id for seen log
+ .ignore_ht = htnew(); // hashtable id for ignored players
+ .roulette = rand(1, 7); // spin the chambers
+ defpattern(.pid, "^(.*)$", "OnTalkNearby");
+ activatepset(.pid);
+ if (.enable_janitor) {
+ initnpctimer();
+ }
+}
+
+// Duplicates below
+//000-1,42,63,0 duplicate(Confused Tree) Confused Palm Tree NPC_NO_SPRITE,14,14
diff --git a/npc/008-1/crane.txt b/npc/008-1/crane.txt
new file mode 100644
index 00000000..3a22fa47
--- /dev/null
+++ b/npc/008-1/crane.txt
@@ -0,0 +1,92 @@
+// TMW scripts.
+// Author:
+// Micksha
+// Description:
+// Crane is Snarfles' apprentice, who secretly eats mouboo steak and enjoys.
+
+008-1,97,113,0 script Crane NPC_SNARFLES,{
+ function foodQuest;
+
+ mesn;
+ mesq l("Heya. I am Crane, Snarfle's apprentice.");
+ if (getq(General_SmearedHands) <= 3 && getq2(General_SmearedHands) != 1)
+ foodQuest();
+ close;
+
+function foodQuest {
+ .@q=getq(General_SmearedHands);
+ next;
+ mesn;
+ mesq l("Don't tell him, but, I secretly love %s!", getitemlink(MoubooSteak));
+ switch (.@q) {
+ case 1:
+ next;
+ mesn strcharinfo(0);
+ select
+ l("Do you know a recipe for %s?", getitemname(BarbecuePlate)),
+ l("Okay, I won't.");
+ mes "";
+ if (@menu == 2)
+ break;
+ mesn;
+ mesq l("Ah sure, it is a simple recipe, I could even make one for you and give you the recipe, but...");
+ next;
+ mesn;
+ mesq l("I always get smeared hands eating it and cannot play cards anymore with Snarfles.");
+ next;
+ mesn;
+ mesq l("Well, if you find me a solution for that problem, I can give you the recipe. What do you say?");
+ next;
+ mesc l("WARNING: If you accept this quest, you'll be struck at the %s route!", b(l("Carnivour"))), 1;
+ mesc l("This will also make %s's Quest unavailable.", b("Snarfles")), 1;
+ mesc l("This decision cannot be changed later."), 1;
+ next;
+ mesc l("Accept this request?"), 1;
+ if (askyesno() == ASK_YES) {
+ setq General_SmearedHands, 2, CARNIVOROUS; // 2 = Carnivorous
+ mesn;
+ mesq l("Great! I'll be eager for your return!");
+ }
+ break;
+ case 2:
+ mesn;
+ mesq l("Have you found a solution for my smeared hands problem?");
+ next;
+ select
+ l("No, not yet.");
+ mes "";
+ mesn;
+ mesq l("I've heard they're related to the earl of sandwich, so maybe a sandwich maker could help... *sigh* I want to play cards...");
+ break;
+ case 3:
+ mesn strcharinfo(0);
+ select
+ l("Have you tried putting it in a bread already?"),
+ l("I'll keep looking for solutions for your problem.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("Actually... No. Have been too afraid of it tasting foul.");
+ next;
+ mesn strcharinfo(0);
+ mesq l("Really? Tiki, Candor's chef, liked it very much.");
+ next;
+ mesn;
+ mesq l("Wha - Really?! Tiki said it tasted good??! I'm saved! You're truly my savior!!");
+ next;
+ mesn;
+ mesq l("I'll put the %s recipe on your %s. Thanks, you saved my day!", getitemlink(BarbecuePlate), getitemlink(RecipeBook));
+ RECIPES[CraftBarbecuePlate]=true;
+ getitembound BarbecuePlate, 1, IBT_ACCOUNT;
+ setq1 General_SmearedHands, 4; // Finished
+ default:
+ return;
+ }
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/doors.txt b/npc/008-1/doors.txt
new file mode 100644
index 00000000..7ad1d705
--- /dev/null
+++ b/npc/008-1/doors.txt
@@ -0,0 +1,43 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Rossy Quest
+
+008-1,49,157,0 script #RossyCaveInit NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ if (getq(HurnscaldQuests_Rossy) != 16)
+ {
+ // Normal warping
+ warp "008-3-0", 129, 112;
+ }
+ else
+ {
+ // HurnscaldQuests_Rossy
+ // (MAIN QUEST, CAVE CONTROL, INSTANCE CONTROL)
+ .@inst=getq3(HurnscaldQuests_Rossy);
+ .@mapn$="ross@"+getcharid(0);
+ // NOTE: .@inst >= 0 skipped now that inst=0 refers to La Marine
+ if (isinstance(.@inst) && instanceowner(.@inst) == getcharid(3))
+ {
+ // Renew instance for 15 minutes
+ //instance_set_timeout(900, 900, .@inst);
+ // FIXME: Clean unkilled monsters
+ } else {
+ .@inst = instance_create("ROSSY "+getcharid(0), getcharid(3), IOT_CHAR);
+ instance_attachmap("008-3-0", .@inst, false, .@mapn$);
+ // Instance lasts 20 minutes
+ instance_set_timeout(ROSSY_INSTIME, ROSSY_INSTIME, .@inst);
+ instance_init(.@inst);
+ setq3 HurnscaldQuests_Rossy, .@inst;
+ // Reset quest progress
+ setq2 HurnscaldQuests_Rossy, 0;
+ @rossylock=false;
+ }
+ // Warp to instanced map
+ warp .@mapn$, 129, 112;
+ }
+ end;
+}
diff --git a/npc/008-1/hinnak.txt b/npc/008-1/hinnak.txt
new file mode 100644
index 00000000..65d050e7
--- /dev/null
+++ b/npc/008-1/hinnak.txt
@@ -0,0 +1,354 @@
+// Evol scripts.
+// Author:
+// gumi, Micksha
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - hinnak asked for help
+// [1] 3 - helped hinnak
+// [2] kill counter
+// Description:
+
+// Hinnak needs help to get rid of the same stuff than ever.
+
+008-1,270,74,0 script Hinnak#008-1 NPC_HINNAK,{
+
+ if (BaseLevel < .min_level)
+ {
+ npctalk3 generic(1 | 16 | 64);
+ end;
+ }
+
+ function hinn_new_player
+ {
+ if(getequipid(EQI_HEAD_TOP) == .bad_hat)
+ {
+ narrator 4,
+ l("The farmer lunges at you with a farming implement.");
+ heal -50, 0;
+
+ selectd
+ l("I'm out of here."),
+ l("Whoa, what are you doing?");
+
+ if (@menu == 1)
+ {
+ return;
+ }
+
+ speech 4 | 1,
+ l("Sorry, you look like a pinkie."),
+ l("They've been destroying my fields, and I guess I got a bit worked up.");
+ }
+
+ else
+ {
+ speech 4,
+ l("Argh!"),
+ l("I hate them!"),
+ l("I @#$% hate them!"),
+ l("I @#$% hate these @#$% pinkies!");
+
+ selectd
+ l("You need some anger control therapy."),
+ l("Why do you hate them?");
+
+ if (@menu == 1)
+ {
+ return;
+ }
+
+ speech 4 | 1,
+ l("These @#$% beasts are jumping around in my fields destroying all my harvest."),
+ l("But they are too fast."),
+ l("I can't catch them.");
+ }
+
+ selectd
+ l("Want me to help you?");
+
+ speech 4 | 1,
+ l("Yes, you look quite fast."),
+ l("Maybe you can catch some of them."),
+ l("That will pay them a lesson."),
+ l("Slay some of them and bring me %d of their antennae.", .drop_count);
+
+ setq .quest, 2, 0;
+
+ selectd
+ l("How much is this worth to you?");
+
+ speech 1,
+ l("Well, I can't offer you much."),
+ l("But I got an old scythe laying around."),
+ l("Maybe you can use it as a weapon.");
+
+ close;
+ }
+
+ function hinn_help
+ {
+ if (getequipid(EQI_HEAD_TOP) == .bad_hat)
+ {
+ narrator 4,
+ l("The farmer glares at your hat.");
+ }
+
+ speech 4,
+ l("Have you got the %d antennae?", .drop_count);
+
+ selectd
+ l("Not yet, but I am working on it."),
+ rif(countitem(.monster_drop) >= .drop_count, l("Sure, here they are!"));
+
+ if (@menu == 1)
+ {
+ return;
+ }
+
+ if (getq2(.quest) < .kill_count)
+ {
+ speech 1,
+ l("Don't try to fool me!"),
+ l("I know you didn't kill them yourself!"),
+ l("Kill at least %d pinkies and come back.", .kill_count);
+ close;
+ }
+
+ speech 1,
+ l("Thank you very much"),
+ l("As promised, here's my old scythe."),
+ l("Maybe you can use it as a weapon."),
+ l("It is a bit cumbersome but its strikes are deadly.");
+
+ if (countitem(.monster_drop) >= .drop_count)
+ {
+ delitem .monster_drop, .drop_count;
+ getitem .reward_item, 1;
+ quest_gp(.maxLevel, .reward_money);
+ //getexp .reward_exp, 0;
+ setq .quest, 3;
+ }
+ close;
+ }
+
+ function hinn_thanks
+ {
+ if (getequipid(EQI_HEAD_TOP) == .bad_hat)
+ {
+ speech 4,
+ l("That better be a trophy on your head.");
+
+ selectd
+ l("It is.");
+
+ speech 4 | 1,
+ l("Good then."),
+ l("Thanks for your help with the pinkies.");
+ }
+
+ else
+ {
+ speech 4,
+ l("Good to see you again."),
+ l("Thanks again for helping me with the pinkies!");
+ }
+
+ selectd
+ l("Sure, any time!"),
+ l("Anything else you want me to do?"),
+ l("You're welcome. Bye!");
+
+ if (@menu == 3)
+ {
+ return;
+ }
+
+ speech 4 | 1,
+ l("Actually, it's been a long day."),
+ l("If it's no trouble, could you get me a %s?",
+ getitemlink(.drink_item));
+
+ selectd
+ rif(countitem(.drink_item) >= 1, l("Here you are.")),
+ l("Sure, I'll go get one. Bye!"),
+ l("You shouldn't drink while working!");
+
+ do
+ {
+ switch (@menu)
+ {
+ case 2: return;
+ case 3:
+ speech 1,
+ l("Well, I'm done for the day, and I'm quite old enough to decide when I can have a %s, thank you!",
+ getitemname(.drink_item));
+ selectd
+ rif(countitem(.drink_item) >= 1, l("Sorry... here you are.")),
+ l("I don't have any.");
+ break;
+ default:
+ if (countitem(.drink_item) < 1)
+ {
+ return;
+ }
+ delitem .drink_item, 1;
+
+ narrator 4 | 8 | 2 | 1,
+ l("%s takes a sip.", .name$);
+
+ speech 4,
+ l("Aaah!"),
+ l("Nothing like a well-deserved %s after a long day of tending the crops!",
+ getitemname(.drink_item)),
+ l("Thanks, that was very kind of you!");
+
+ narrator 4 | 8 | 1 | 2,
+ l("He takes another sip.");
+
+ speech 4,
+ l("Thanks!"),
+ l("You know, I had the strangest thing happen to me."),
+ l("I had this patch of ground that was really clumpy; lots of clay, you see."),
+ l("Right over there."),
+ // TODO: move cam to the spot
+ l("Looks much better now, doesn't it?"),
+ // TODO: restore cam
+ l("But how I got there is kind of scary..."),
+ l("I'd been trying to break it up for a while, but that kind of work is a pain."),
+ l("So my wife said that I should go and see the witch, just in case she knows something."),
+ l("And sure enough I ask the witch, and she has a look at it."),
+ l("“Nothing I can do”, she says, “but I can ask a friend”."),
+ l("So the next day another witch shows up."),
+ l("Gorgeous woman, but when she looked at me, the scares went scuttling down my spine..."),
+ l("First thing she asked was if I'm a farmer."),
+ l("Said her friend had told her that I needed help."),
+ l("I show her what the problem is, and she tells me to go inside and wait.");
+
+ narrator 4 | 8 | 1 | 2,
+ l("%s drains his mug in one long sip, then hesitates.", .name$);
+
+ speech 4,
+ l("So I go inside."),
+ l("I'm barely in when it starts raining outside, pouring cats and mouboos!"),
+ l("Not so weird, perhaps, except that it was been bright and sunny just a second before!"),
+ l("So I rush out, my wife telling me to leave the witch alone, and I see her standing there in the middle of the rain..."),
+ l("None of the raindrops touched her, as if they were afraid!"),
+ l("Then she yells out some gobbledygook word, and out of the ground there comes a swarm of maggots, crawling and digging and climbing over each other's backs..."),
+ // XXX: maybe here insert a reference to SUSAN?
+ l("And then she turns to me!"),
+ l("Seeing her gaze, for a moment there I thought she would turn me into a pinkie, for sure..."),
+ l("But all she says is, “had you stayed inside, you wouldn't be wet now”.");
+
+ selectd
+ l("Hahaha!"),
+ l("Whoah, scary..."),
+ l("What was that gobbledygook word?"),
+ l("I better go now. Bye.");
+
+ switch (@menu)
+ {
+ case 1:
+ speech 1,
+ l("Yeah, funny now..."),
+ l("But you should've seen that gaze!"),
+ l("Ah, well, never mind.");
+ close;
+ case 2:
+ speech 1,
+ l("Yeah, you could say that...");
+ close;
+ case 3:
+ speech 1,
+ l("Oh, I can't be sure..."),
+ l("But something like “Nanaj princino”, I think."); // this is "Dwarven Princess" translated to Esperanto
+ close;
+ }
+ return;
+ }
+ } while(true);
+ }
+
+ // OnTalk:
+
+ if (getq(.quest_inspector) == 11)
+ {
+ selectd
+ l("Did you see anyone in a mask come by here at night?"),
+ l("Did you see anyone with a large satchel come by here at night?"),
+ l("Hello.");
+
+ switch (@menu)
+ {
+ case 1:
+ speech
+ l("No."),
+ l("It tends to be too dark to see a mask.");
+ close;
+
+ case 2:
+ speech
+ l("Yes, I saw someone with a large sack on their back go to the mining camp.");
+ close;
+ }
+ }
+
+ switch (getq(.quest))
+ {
+ case 0:
+ case 1: hinn_new_player; break;
+ case 2: hinn_help; break;
+ default: hinn_thanks;
+ }
+
+ closeclientdialog();
+ close;
+
+OnNPCKillEvent:
+ // XXX: maybe have a OnTakeScript on the pinky antena item so we count pickups instead of kills
+ if (killedrid == .monster_id && getq(.quest) == 2 &&
+ getq2(.quest) < .kill_count && strcharinfo(PC_MAP) == .map$)
+ {
+ setq .quest, 2, getq2(.quest) + 1;
+ }
+ end;
+
+OnPCLoginEvent:
+OnPCBaseLvUpEvent:
+ if (BaseLevel >= .min_level && getq(.quest) < 1)
+ {
+ setq .quest, 1; // allow the player to do the quest
+ dispbottom l("New quest available: %s (level %d+)",
+ getquestlink(.quest), .min_level); // XXX: requires new manaplus versions, maybe show a different message for old versions?
+ }
+ end;
+
+OnInit:
+ .min_level = 15; // min level to do the quest
+ .maxLevel = getiteminfo(Scythe, ITEMINFO_ELV) + 20;
+ .monster_id = Pinkie; // monster to kill
+ .monster_drop = PinkAntennae; // monster drop to collect
+ .drop_count = 10; // amount of that drop needed
+ .kill_count = 10; // min number of kills
+ .reward_item = Scythe; // reward item
+ .reward_money = 0; // reward money
+ .reward_exp = 0; // reward exp
+ .bad_hat = PinkieHat; // hinnak attacks you when you wear this hat
+ .drink_item = Beer; // the item hinnak asks to drink
+
+ .quest = HurnscaldQuests_Hinnak;
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
+
diff --git a/npc/008-1/jack.txt b/npc/008-1/jack.txt
new file mode 100644
index 00000000..fd16d965
--- /dev/null
+++ b/npc/008-1/jack.txt
@@ -0,0 +1,314 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states (forest bow):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - alan wants to ask jack
+// [1] 3 - jack explained problem
+// [1] 4 - alan asks to find wood
+// [1] 5 - found perfect wood
+// [1] 6 - got the bow
+// [2] fail count
+// [3] unused
+// [t] unused
+// Quest states (wooden shield):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - jack proposes shield
+// [1] 3 - player accepted quest
+// [1] 4 - got the shield
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// Jack Lumber, the handsome lumberjack
+
+
+008-1,241,116,0 script Jack NPC_LUMBERJACK,{
+
+ function bow_intro {
+ speech(4,
+ l("Why not?!"),
+ l("I value my life, that's why!"));
+
+ selectd(l("What do you mean?"));
+
+ speech(4,
+ l("A week ago, I was going to chop down one of those twigleaf trees in the forest to the southwest."),
+ l("These twigleafs are the trees that give me the living wood you speak of."), // XXX: were Log Heads named "Twigleaf" at some point in the past?
+ l("I was just chopping away with my axe, and guess what happened?"),
+ l("One of its branches hit me!"),
+ l("At first, I thought it fell down or the wind blew it, but it hurt!"),
+ l("After I shook it off and struck the tree again with my axe, another branch hit me!"),
+ l("I got angry and started to chop off all the low-hanging branches so this couldn't happen anymore."),
+ l("Even after all that though, I still can't believe what happened next."));
+
+ selectd(l("What happened?"));
+
+ speech(4,
+ l("You'll think I'm insane if I tell you..."));
+
+ selectd(l("I won't. I promise."));
+
+ speech(4,
+ l("Alright, well..."),
+ l("After I chopped off a few branches, the whole tree started to move!"),
+ l("Its roots tore out of the earth, all the branches started to wave around, and a face appeared on the trunk."),
+ l("The whole tree CAME TO LIFE! It was mad!"));
+
+ selectd(l("Did you run away?"), l("Did you fight it?"));
+
+ speech(4,
+ l("I fought it, of course!"),
+ l("I took my axe and attacked the beast!"),
+ l("It hit me here *points at a bruise on his shoulder*, here *lifts his trouser leg to show another bruise*, and here *lifts his shirt and reveals even worse bruises*."), // XXX: that's kinda dirty imho... maybe we could use the narrator?
+ l("But I didn't give up!"),
+ l("I chopped away at it, branch after branch, and in the end I chopped off its roots, and it fell to the ground, motionless."));
+
+ selectd(l("So you beat the monster? Then why are you so scared?"));
+
+ speech(4,
+ l("Well, I was exhausted and had to rest."),
+ l("A few minutes passed, and suddenly I was practically surrounded by a dozen or more of these living trees!"));
+
+ selectd(l("Did you fight them too?"));
+
+ speech(4,
+ l("Are you crazy?"),
+ l("I barely destroyed one of those beasts."),
+ l("I was in no shape to fight again!"),
+ l("I ran away as fast as I could, and lucky for me the monsters aren't that fast on their tiny root legs, Ha!"));
+
+ selectd(l("So, I guess you aren't chopping down trees anymore?"));
+
+ speech(4,
+ l("I still do; it's my job."),
+ l("But I'll no longer chop those twigleafs, I'll tell you that."),
+ l("I know the bow master wants some twigleaf wood, but I don't care."),
+ l("I won't risk MY life for a few gold pieces!"),
+ l("If you really want to, just go to the southwest, but I can't help you."),
+ l("I won't go there ever again."));
+
+ selectd(l("Southwest you say? OK, thank you."));
+
+ speech(l("Don't say I didn't warn you!"));
+
+ // What a huge text wall, I feel sorry for the players
+
+ close2;
+ setq(.quest_bow, 3);
+ end;
+ }
+
+ function bow_good_luck {
+ if (getq(.quest_inspector) == 2)
+ {
+ speech(4,
+ l("Good luck hunting those tree monsters – you'll need it."));
+
+ selectd(l("Have you seen anything that might be connected to the recent robberies in town?"));
+
+ speech(l("Sorry, no."));
+ close;
+ }
+
+ npctalk3(l("Good luck hunting those tree monsters – you'll need it."));
+ end;
+ }
+
+ function shield_intro {
+ speech(4,
+ l("I have an idea."),
+ l("What would you say about a new shield?"));
+
+ setq(.quest_shield, 2);
+
+ selectd(
+ l("No thanks."),
+ l("Yes, please!"),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")));
+
+ switch (@menu)
+ {
+ case 1: closeclientdialog(); close;
+ case 2:
+ speech(
+ l("All I need is %d %s.", .logs_amount, getitemlink(.logs_item)),
+ l("This needn't be high quality wood; pretty much any log you can find should work."),
+ l("Oh, and I'll also need %s E for other materials.", format_number(.shield_cost)));
+
+ close2;
+ setq(.quest_shield, 3);
+ end;
+ case 3: speech(l("Sorry, no.")); close;
+ }
+ }
+
+ function bow_congrats {
+ speech(4,
+ l("You've finally found that perfect piece of living wood that Alan needs to make a Forest Bow, haven't you?"));
+
+ selectd(
+ l("I couldn't afford the bow, though..."),
+ l("No, I'm still looking."),
+ l("Yes, I've got the Forest bow now."),
+ l("I'm a melee warrior, I don't need bows."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")));
+
+ switch (@menu)
+ {
+ case 3:
+ if (getq(.quest_bow) <= 5)
+ {
+ speech(4,
+ l("Hrmph."),
+ l("I'm someone who respects those speaking the truth."));
+ }
+ // fallthrough
+ case 1:
+ case 4:
+ speech(4,
+ l("You no doubt remember how I struggled with those beasts, fighting for my life."),
+ l("Scared me, those seven-branched little stumps did!"),
+ l("Never since that day have I strayed near them, and yet there you are, cutting them down one by one."),
+ l("I'm proud of you – to dare to fight those trunks is admirable indeed."),
+ l("You're as strong as if you were my own child!"));
+
+ shield_intro;
+ break;
+ case 2: speech(l("You should go talk to Alan again.")); close;
+ case 5: speech(l("Sorry, no.")); close;
+ }
+ }
+
+ function shield_make {
+ speech(4,
+ l("Do you have the %d %s and %s E for the shield?",
+ .logs_amount, getitemlink(.logs_item), format_number(.shield_cost)));
+
+ selectd(
+ rif(countitem(.logs_item) >= .logs_amount && Zeny >= .shield_cost,
+ l("Here it is.")),
+ l("I'll come back later."));
+
+ if (@menu != 1) {
+ closeclientdialog();
+ close;
+ }
+
+ speech(4,
+ l("Have a seat."));
+
+ narrator(4,
+ l("Jack saws the logs into pieces and then sands them until they are smooth to the touch."),
+ l("Applying some strong-smelling liquid, he tans them to a darker hue."),
+ l("Grabbing one of two leftover pieces, he begins to carve it into a round shape, then repeats this with the second piece – shield handles from what you can tell."),
+ l("Meanwhile, the sun has dried the other pieces."),
+ l("Jack places them next to each other, adds a frame, and nails everything together."),
+ l("The resulting shield looks usable already, but Jack applies another liquid to it and leaves it to dry for a few moments."),
+ l("Finally, he hands the shield to you."));
+
+ if (checkweight(.shield_item, 1) != true)
+ {
+ speech(
+ l("It seems you can't carry the %s.", getitemlink(.shield_item)),
+ l("Come back when you do."));
+ close;
+ }
+
+ if (Zeny < .shield_cost || countitem(.logs_item) < .logs_amount)
+ close; // double-check
+
+ setq(.quest_shield, 4);
+ delitem(.logs_item, .logs_amount);
+ getitem(.shield_item, 1);
+ Zeny -= .shield_cost;
+ quest_xp(.maxLevel, .shield_exp);
+
+ speech(
+ l("Enjoy your new shield!"));
+
+ close;
+ }
+
+ function wood_daily {
+ speech(4,
+ l("I hope that my shield will serve you well!"));
+
+ selectd(
+ l("Me too."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")));
+
+ switch (@menu)
+ {
+ case 2: speech(l("Sorry, no.")); close;
+ }
+
+ closeclientdialog(); // TODO: daily quest (needs the generic daily quest script)
+ close;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_shield))
+ {
+ case 2: shield_intro; break;
+ case 3: shield_make; break;
+ case 4: wood_daily; break;
+ }
+
+ switch (getq(.quest_bow))
+ {
+ case 3:
+ case 4: bow_good_luck; break;
+ case 5:
+ case 6: bow_congrats; break;
+ }
+
+ // initial intro
+ {
+ speech(4,
+ l("Hello there!"),
+ l("My name is Jack Lumber, the enemy of all trees."),
+ l("If you need some firewood, just let me know."));
+
+ selectd(
+ l("I'll keep that in mind."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")),
+ rif(getq(.quest_bow) == 2, l("I heard you aren't delivering any more living wood. Why not?")));
+
+ switch (@menu)
+ {
+ case 2: speech(l("Sorry, no.")); close;
+ case 3: bow_intro; break;
+ }
+
+ }
+
+ closeclientdialog();
+ close;
+
+OnInit:
+ .logs_item = RawLog;
+ .logs_amount = 40; // XXX: maybe nlogn?
+ .shield_cost = 5000; // XXX: maybe nlogn?
+ .shield_exp = 2500;
+ .shield_item = WoodenShield;
+ .maxLevel = getiteminfo(WoodenShield, ITEMINFO_ELV) + 20;
+
+ .quest_bow = HurnscaldQuests_ForestBow;
+ .quest_shield = HurnscaldQuests_WoodenShield;
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_bow;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/mapflags.txt b/npc/008-1/mapflags.txt
new file mode 100644
index 00000000..f2680964
--- /dev/null
+++ b/npc/008-1/mapflags.txt
@@ -0,0 +1 @@
+008-1 mapflag town
diff --git a/npc/008-1/marine.txt b/npc/008-1/marine.txt
new file mode 100644
index 00000000..ca448a2e
--- /dev/null
+++ b/npc/008-1/marine.txt
@@ -0,0 +1,17 @@
+// Moubootaur Legends scripts.
+// Authors:
+// Jesusalva
+// Description:
+// This script controls access to Ships, fixing variables.
+
+// Use NPC_LA_MARINE if needed
+008-1,327,104,0 script La Marine#H NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ EnterTown("Hurns");
+
+ warp "marine@"+LOCATION$, 42, 26;
+ closedialog;
+ close;
+}
diff --git a/npc/008-1/mikhail.txt b/npc/008-1/mikhail.txt
new file mode 100644
index 00000000..24806baf
--- /dev/null
+++ b/npc/008-1/mikhail.txt
@@ -0,0 +1,123 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - bernard wants roasted maggot
+// [1] 3 - brought maggot
+// [1] 4 - bernard wants maggot slime
+// [1] 5 - brought maggot slime
+// [1] 6 - mikhail needs maggot slime
+// [1] 7 - brought maggot slime
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// takes part in the slime soup quest (Bernard)
+
+008-1,298,95,0 script Mikhail NPC_MIKHAIL,{
+
+ function soup_scared {
+ speech 4,
+ l("Hello..."),
+ l("I'm supposed to be helping Bernard from the Inn but...");
+
+ narrator 4,
+ l("His eyes grow wide");
+
+ speech 4,
+ l("Eeekkk another one.");
+
+ narrator
+ l("It seems that the boy would like to say more, but seems too terrified at the moment."),
+ l("Maybe you should help someone else first, so that he sees your intentions are good.");
+
+ close;
+ }
+
+ function soup_intro2 {
+ speech 4,
+ l("Bernard sent me to get %d %s from the %s in the fields, but they scare me so bad!",
+ .third_item_qty, getitemlink(.third_item), getmonsterlink(.third_item_mob)),
+ l("You look like a nice person."),
+ l("Would you go get them for me?");
+
+ selectd
+ l("Of course, I'll go get them for you.");
+
+ speech
+ l("Thank you so much!"),
+ l("I'll wait for you here.");
+
+ setq .quest, 6;
+ close;
+ }
+
+ function soup_reminder_slime2 {
+ speech
+ l("Did you bring me the %d %s I need?",
+ .third_item_qty, getitemlink(.third_item)),
+ l("It doesn't look like you have them all...");
+ close;
+ }
+
+ function soup_reward_slime2 {
+ speech
+ l("Did you bring me the %d %s I need?",
+ .third_item_qty, getitemlink(.third_item)),
+ l("Ooh!"),
+ l("Thank you so much!"),
+ l("I can get back to Bernard now!");
+
+ if (countitem(.third_item) < .third_item_qty)
+ close; // double-check
+
+ delitem .third_item, .third_item_qty;
+ setq .quest, 7;
+ quest_xp(.maxLevel, .third_reward_exp);
+ close;
+ }
+
+ function soup_thanks_slime2 {
+ speech
+ l("Thanks again for helping me!") + " %%Q";
+
+ close;
+ }
+
+ switch(getq(.quest))
+ {
+
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4: soup_scared; break;
+ case 5: soup_intro2; break;
+ case 6:
+ if (countitem(.third_item) < .third_item_qty)
+ soup_reminder_slime2;
+ else
+ soup_reward_slime2;
+ break;
+ default: soup_thanks_slime2;
+ }
+
+ closeclientdialog();
+ close;
+
+OnInit:
+ .third_item = MaggotSlime;
+ .third_item_qty = 5;
+ .third_item_mob = Maggot;
+
+ .maxLevel = 30;
+ .third_reward_exp = 100;
+
+ .quest = HurnscaldQuests_Soup;
+ .quest_debug = .quest;
+ .distance = 3;
+
+ end;
+}
diff --git a/npc/008-1/milly.txt b/npc/008-1/milly.txt
new file mode 100644
index 00000000..320ef3bf
--- /dev/null
+++ b/npc/008-1/milly.txt
@@ -0,0 +1,119 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states (inspector):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+// Give player a Beanie Copter after 1,000,000 kills (server-wide)
+function script GetBeanieCopter {
+ // Double-check against possible malpractices
+ if ($MONSTERS_KILLED % 1000000 == 0) {
+ announce(sprintf("Congratulations, \"%s\", on killing the %sth monster!.", strcharinfo(0), format_number($MONSTERS_KILLED)), bc_all);
+ getitem BeanieCopter, 1;
+ dispbottom l("How strange, this monster dropped a very rare hat!");
+ }
+ return;
+}
+
+008-1,282,114,0 script Milly NPC_GIRL_MILLY,{
+
+ // TODO: make the actual beanie copter quest after those are finished:
+ // [X] Inspector quest
+ // [ ] Bone knife quest
+ // [ ] Setzer quest
+ // [ ] Rossy quest
+ // [ ] Cindy quest
+
+ .@q_inspector = getq(.quest_inspector);
+
+ speech(4,
+ l("Hello traveler, welcome to Hurnscald."),
+ l("Have you met Kfahr yet?"),
+ l("He is the greatest hero that ever walked the land of Hurnscald!"));
+
+ selectd(
+ l("Hi! No, I haven't seen him yet."),
+ l("Where can I find him?"),
+ l("Mh, I don't care for heroes."),
+ l("Hello, yes I have met him."),
+ rif(.@q_inspector == 2, l("Have you seen anything strange lately?")),
+ rif(.@q_inspector == 2, l("Do you know anything about the recent robberies?")));
+
+ switch (@menu)
+ {
+ case 3:
+ speech(4,
+ l("What?"),
+ l("Surely you do not appreciate what a hero he is!"),
+ l("Mh, or perhaps honor is dead in you; for you to be so slow to comprehend the good that his exploits have wrought for us."), // XXX: this sentence seems too complicated to come from a child's mouth
+ l("Put on your thinking cap and be propelled into high adventure!"),
+ l("Go to Kfahr, and listen to his stories."),
+ l("You can't have met him."),
+ l("No one who has met him would say such silly things."));
+ // fallthrough
+
+ case 1:
+ speech(4,
+ l("I highly recommend you seek him out!"));
+ // fallthrough
+
+ case 2:
+ speech(
+ l("He is a regular at the inn, located in the north-west part of town."),
+ l("If you are lucky he might tell you a story about his adventures."));
+ break;
+
+ case 4:
+ speech(
+ l("Oh, I hope you stayed and listened to his stories about his adventures."));
+ break;
+
+ case 5:
+ speech(
+ l("I haven't seen anything strange."));
+ break;
+
+ case 6:
+ speech(
+ l("No, sorry."));
+ break;
+ }
+
+ close;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector; // TODO: change this to the milly quest debug when it exists
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/old-man.txt b/npc/008-1/old-man.txt
new file mode 100644
index 00000000..5b0e2f51
--- /dev/null
+++ b/npc/008-1/old-man.txt
@@ -0,0 +1,89 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-1,290,139,0 script Old Man NPC_OLD_MAN_HURNS,{
+
+ function oldman_ask {
+ speech(4,
+ l("Hi there, need something?"));
+
+ selectd(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ speech(
+ l("I'm sorry, but I didn't see anything."),
+ l("You should ask my old woman."));
+ close;
+ }
+
+ function oldman_accuse {
+ speech(4,
+ l("Found anything new?"));
+
+ selectd(
+ l("The leader of the troupe said you hung around them a lot while they were in town."));
+
+ speech(
+ l("Yes, I hung around the theater a lot."),
+ l("I was an actor when I was younger."),
+ l("But I wasn't there that night."),
+ l("Me and the wife were at home all night."));
+
+ close2;
+ setq(.quest_inspector, 8);
+ end;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_inspector))
+ {
+ case 2: oldman_ask; break;
+ case 7: oldman_accuse; break;
+ }
+
+ // initial intro
+ npctalk3(l("Don't let those monsters get to you."));
+ end;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 1; // this npc has bad hearing
+ .speed = 2000; // this npc is very old
+ // TODO: move graph (after the Hurnscald map is finalized)
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/old-woman.txt b/npc/008-1/old-woman.txt
new file mode 100644
index 00000000..89789b70
--- /dev/null
+++ b/npc/008-1/old-woman.txt
@@ -0,0 +1,136 @@
+/// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// Old Lady in the flower field, Robberies in Hurnscald.
+
+008-1,231,114,0 script Old Woman NPC_OLD_LADY,{
+
+ function is_inspector {
+ return (getequipcardid(EQI_HEAD_MID, 0) == NavyBlueCottonDye &&
+ getequipcardid(EQI_HEAD_LOW, 0) == NavyBlueCottonDye);
+ }
+
+ function oldwoman_ask {
+ speech(4,
+ l("Hello deary."));
+
+ selectd(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ .@q = getq(.quest_inspector);
+
+ if (!is_inspector())
+ {
+ speech(l("Yes, but I'm only talking to the inspector himself!"));
+
+ close2;
+ if (.@q < 3)
+ setq(.quest_inspector, 3);
+ end;
+ }
+
+ if (.@q == 2 || .@q == 3)
+ {
+ speech(
+ l("I saw someone sneaking around town wearing a theater mask."),
+ l("It looked like one of the masks used by the troupe that was in town recently."));
+
+ close2;
+ setq(.quest_inspector, 4);
+ }
+
+ else if (.@q == 10)
+ {
+ speech(
+ l("I've remembered something else."),
+ l("The night the troupe left, I saw someone with a theater mask take a large satchel out of town."),
+ l("He was heading north."));
+
+ close2;
+ setq(.quest_inspector, 11);
+ }
+
+ end;
+ }
+
+ function oldwoman_alibi {
+ speech(4,
+ l("Hello deary."));
+
+ selectd(
+ l("Was your husband with you at home all night the last night that the troupe was in town?"));
+
+ speech(
+ l("Yes, we were both at home all night."));
+
+ close2;
+ setq(.quest_inspector, 9);
+ end;
+ }
+
+ function oldwoman_filler {
+ npctalk3(l("I hope you catch that naughty person!"));
+ end;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_inspector))
+ {
+ case 2:
+ case 3: oldwoman_ask; break;
+ case 4:
+ case 5:
+ case 6:
+ case 7: oldwoman_filler; break;
+ case 8:
+ case 9: oldwoman_alibi; break;
+ case 10: oldwoman_ask; break;
+ }
+
+ // initial intro
+ if (BaseLevel < 40)
+ npctalk3(l("Watch out for these flowers. They don't like to be messed with."));
+ else
+ npctalk3(l("Hello deary."));
+ end;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 1; // this npc has bad hearing
+ .speed = 2000; // this npc is very old
+ // TODO: move graph (after the Hurnscald map is finalized)
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/oscar.txt b/npc/008-1/oscar.txt
new file mode 100644
index 00000000..2ea42456
--- /dev/null
+++ b/npc/008-1/oscar.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Oscar the farmer.
+// THIS IS A PLACEHOLDER! Read Dimond Chef before editing.
+
+008-1,160,77,0 script Oscar NPC_CAUL,{
+ speech
+ l("Hi, my name is Oscar."),
+ l("I used to be a farmer, but my magic attempts were banned by the gouvernment."),
+ l("Now I remain poor and unemployed.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/rossy.txt b/npc/008-1/rossy.txt
new file mode 100644
index 00000000..f0acfa67
--- /dev/null
+++ b/npc/008-1/rossy.txt
@@ -0,0 +1,391 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Daughter of Olana and sister of Juliet. PLACEHOLDER SPRITE
+
+008-1,62,220,0 script Rossy NPC_TANISHA,{
+ function rossyFirstmet;
+ function rossyBasket;
+ function rossyLetter;
+ function rossyPotionList;
+ function rossyPotionDone;
+ function rossyDeliverRoses;
+ function rossyDeliverTulip;
+ function rossyJulietIntro;
+ .@q=getq(HurnscaldQuests_Rossy);
+ mesn;
+ mesq l("Hello, wanderer.");
+ switch (.@q) {
+ case 1:
+ rossyFirstmet();
+ break;
+ case 3:
+ rossyBasket();
+ break;
+ case 6:
+ rossyLetter();
+ break;
+ case 7:
+ rossyPotionList();
+ break;
+ case 8:
+ mesn;
+ mesq l("What, you still have my potion with you??");
+ next;
+ mesn;
+ mesq l("Could you please deliver it to %s in the magic academy? He is the head of alchemy.", b("David"));
+ break;
+ case 9:
+ case 10:
+ rossyPotionDone();
+ break;
+ case 11:
+ rossyDeliverRoses();
+ break;
+ case 13:
+ rossyDeliverTulip();
+ break;
+ case 14:
+ mesn;
+ mesq l("Go and tell my mother that she is the nicest mother in the world.");
+ next;
+ select
+ l("Right on it."),
+ l("Did you find your sister? I am starting to get worried too.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ if (BaseLevel < .minLevel_rescue)
+ mesq l("I think I have an idea where Juliet might be. Come back in a few levels, and I will tell you if she is ok.");
+ else
+ mesq l("I think I have an idea where she might be. Come back in a few minutes, I will tell you if she is ok.");
+ }
+ break;
+ case 15:
+ rossyJulietIntro();
+ break;
+ case 16:
+ mesn;
+ mesq l("Oh no! Juliet ... why would you go to that scary place? ... Please help her, %s!", strcharinfo(0));
+ mesc l("The cave is %s", b(l("Northwest of here.")));
+ break;
+ case 17:
+ mesn;
+ mesq l("Hey %s!", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("Thanks for finding Juliet again. I'm so relieved!");
+ next;
+ mesn;
+ mesq l("...I still wonder what was that thing Juliet was running from... Hm? Nothing! Just thinking out loud.");
+ break;
+ // Default messages
+ case 12:
+ mesc l("Achooo!");
+ // FALLTHROUGH
+ default:
+ mesn;
+ mesq l("I'm being lazy right now, so please %s", any(
+ l("don't tell devs I'm slacking off again."),
+ l("tell my mother there is no reason to worry."),
+ l("don't worry with me.")
+ ));
+ }
+ close;
+
+function rossyFirstmet {
+ mesc l("A young girl looks at you in tears.");
+ next;
+ select
+ l("Hey there... Why are you crying? Are you hurt?"),
+ l("Sorry kid, I don't have time to play with children.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn l("Young Girl");
+ mesq l("No. I'm crying because I lost all my fruits. My sister and I were collecting some near Dimond's Cove, but then I stumbled on a giant snail and it attacked us!");
+ next;
+ mesn l("Young Girl");
+ mesq l("But we were lucky, because the snail is really slow and we ran away from it. Juliet ran to the left and I ran to the right. The snail got pretty confused, because we are identical twins. The problem is that I dropped the basket full of fruits on the ground and that evil snail ate them all! And now I can't find Juliet to help me collect more fruits.");
+ next;
+ mesn strcharinfo(0);
+ select
+ l("Did you say \"Juliet\"? I talked to your mother Olana, She's very worried about you!");
+ mes "";
+ // You know she is Rossy, so mesn; won't need args anymore
+ mesn;
+ mesq l("Really? But she let us play in the woods. There's no reason to be worried – unless....");
+ next;
+ mesn;
+ mesc l("Rossy suddenly gets a strange look on her face, mumbling something about Juliet.");
+ mesq l("Could you do me a favor? Please, tell my mother that we're alright. There's ... well ... there's no reason to worry about us.");
+ next;
+ select
+ l("Very well, if you say so...."),
+ l("Sorry, but I really don't have time for this.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Then why bother? Weird person...");
+ return;
+ }
+ setq HurnscaldQuests_Rossy, 2;
+ mesn;
+ mesq l("Thank you very much!");
+ return;
+}
+
+function rossyBasket {
+ mesn;
+ mesq l("Hey, that is nice of you to come back. I was thinking about giving a basket full of %s to my mother, to make her happy, you know.", getitemlink(Blueberries));
+ next;
+ mesn;
+ mesq l("But I would need at least %d berries, and it would take ages to get so many by myself!", .blueberries_amount);
+ next;
+ select
+ l("That is no problem for me. Just wait and I will come back with the cherries."),
+ l("Ask Juliet, not me."),
+ rif(countitem(Blueberries), l("Hey, I have some in my backpack!")),
+ l("You should get them yourself.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Juliet ran to the left, and I'm pretty sure she is doing the same.");
+ }
+ if (@menu != 3)
+ return;
+ if (countitem(Blueberries) < .blueberries_amount) {
+ mesn;
+ mesq l("You do, but that's not enough. I need %d %s.", .blueberries_amount, getitemlink(Blueberries));
+ }
+ delitem Blueberries, .blueberries_amount;
+ quest_xp(.maxLevel, 2000);
+ quest_jxp(.maxLevel, 500);
+ setq HurnscaldQuests_Rossy, 4;
+ // FIXME: Perhaps give player a [Berries Bag] item? Hmm.
+ mesn;
+ mesq l("I can't believe it! You got all the berries needed! Lemme just wrap them and... done! Please give them to my mother. Tell her that it is a gift from me and Juliet, and that there's no reason to worry about us."); // Lemme = Let me
+ next;
+ mesn;
+ mesc l("%s mumbles to herself.", .name$);
+ mesq l("I hope...");
+ next;
+ mesn;
+ mesq l("Oh, and after you give the berries to my mother, please come back here. Err, if you have some free time, of course.");
+ return;
+}
+
+function rossyLetter {
+ mesn;
+ mesq l("I'm being lazy right now, so please %s", any(
+ l("don't tell devs I'm slacking off again."),
+ l("tell my mother there is no reason to worry."),
+ l("don't worry with me.")
+ ));
+ next;
+ select
+ l("Hocus sent a letter to you."),
+ l("Erm, okay.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("The Grandmaster? %%U Lemme read...");
+ next;
+ mesn;
+ mesc l("%s's face suddenly turns pale.", .name$);
+ mesq l("Oh no! I completely forgot. The exam! Dang, I knew I should not have picked Alchemy for study...");
+ next;
+ mesn;
+ mesc l("%s looks at you with beady eyes.", .name$);
+ mesq l("I haven't found Juliet yet, and I don't even have any of the ingredients required. Could you get them for me? Pretty please? %%J");
+ next;
+ select
+ l("Alright, tell me what I must get."),
+ l("Your cute face will not convince me - Your test, your responsibility.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Yes, I know. I really should have started it earlier... But I can't look for Juliet AND get the ingredients at the same time. Some of them are only found in Tulimshar.");
+ next;
+ mesn;
+ mesq l("You don't even know how Juliet looks. Please come back if you reconsider. Please. Juliet could be being eaten by a creature, as we speak. %%i");
+ return;
+ }
+ setq HurnscaldQuests_Rossy, 7, 0;
+ mesn;
+ mesq l("Excellent! So, as for the materials I need to brew the potion...");
+ next;
+ rossyPotionList();
+ return;
+}
+
+function rossyPotionList {
+ .@t=getq2(HurnscaldQuests_Rossy);
+ // Potion submitted
+ if (.@t) {
+ // Finished!
+ if (.@t < gettimetick(2)) {
+ // Yay
+ mesn;
+ mesq l("I'm done! Thanks for the help. It is just the shade of blue I wanted.");
+ next;
+ mesn;
+ mesq l("Could you please deliver it to %s in the magic academy? He is the head of alchemy.", b("David"));
+ setq HurnscaldQuests_Rossy, 8, 0;
+ } else {
+ // Brewing
+ mesn;
+ mesq l("Please be patient... I'll be done in %s.", FuzzyTime(.@t));
+ }
+ return;
+ }
+
+ // Potion not yet finished
+ //mesf("- %d/%d %s", countitem(CactusDrink), 24, getitemlink(CactusDrink));
+ mesf("- %d/%d %s", countitem(MaggotSlime), 32, getitemlink(MaggotSlime));
+ mesf("- %d/%d %s", countitem(GambogeHerb), 50, getitemlink(GambogeHerb));
+ mesf("- %d/%d %s", countitem(AlizarinHerb), 43, getitemlink(AlizarinHerb));
+ mesf("- %d/%d %s", countitem(BugLeg), 30, getitemlink(BugLeg));
+ mesf("- %d/%d %s", countitem(Pearl), 1, getitemlink(Pearl));
+ next;
+ mesn;
+ mesq l("Do you have these materials with you?");
+ next;
+ select
+ l("Not yet."),
+ l("Yes, here they are!"),
+ l("No, but I'll be right back.");
+ mes "";
+ if (@menu != 2)
+ return;
+ if (countitem(MaggotSlime) < 32 ||
+ countitem(GambogeHerb) < 50 ||
+ countitem(AlizarinHerb) < 43 ||
+ countitem(BugLeg) < 30 ||
+ //countitem(CactusDrink) < 24 ||
+ countitem(Pearl) < 1) {
+ mesn;
+ mesq l("You would lie to a poor, small, frail girl like me? %%S");
+ next;
+ mesn;
+ mesq l("Don't you think that to be very coward on your part?");
+ return;
+ }
+ //delitem CactusDrink, 24;
+ delitem MaggotSlime, 32;
+ delitem GambogeHerb, 50;
+ delitem AlizarinHerb, 43;
+ delitem BugLeg, 30;
+ delitem Pearl, 1;
+ setq2 HurnscaldQuests_Rossy, gettimetick(2)+900;
+ mesn;
+ mesq l("Perfect! Please allow me some time to brew this potion. It should be ready in 15 minutes or so.");
+ return;
+}
+
+function rossyPotionDone {
+ mesn;
+ mesq l("So... How did it go?");
+ next;
+ select
+ l("David said it was \"okay-ish\"."),
+ l("David said he would grade it later, but you had nothing to worry about.");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("That's a relief. Okay-ish is actually a pretty good grade in the Academy.");
+ next;
+ }
+ mesn;
+ mesq l("Could you please tell my mother about that? She is already worried with Juliet and me, no need to have her worried about the exam as well.");
+ compareandsetq HurnscaldQuests_Rossy, 9, 10;
+ return;
+}
+
+function rossyDeliverRoses {
+ if (countitem(ARedRose) < 15) {
+ mesn;
+ mesq l("Hello %s.", strcharinfo(0));
+ return;
+ }
+ select
+ l("Your mother was so happy that she asked me to bring you these flowers.");
+ mes "";
+ delitem ARedRose, 15;
+ setq HurnscaldQuests_Rossy, 12;
+ mesn;
+ mesq l("How nice!");
+ next;
+ mesn;
+ mesc l("Rossy takes the flowers from your hands and suddenly throws them on the ground. She begins sneezing.");
+ next;
+ select
+ l("I presume you don't like roses, right?"),
+ l("Are you feeling well?");
+ mes "";
+ mesn;
+ mesq l("I am allergic to roses; my mother should already know that!");
+ next;
+ mesn strcharinfo(0);
+ mesc l("Maybe we should talk to Olana about this.");
+ return;
+}
+
+function rossyDeliverTulip {
+ if (countitem(ARedTulip) < 15) {
+ mesc l("Achooo!");
+ mesn;
+ mesq l("I'm being lazy right now, so please %s", any(
+ l("don't tell devs I'm slacking off again."),
+ l("tell my mother there is no reason to worry."),
+ l("don't worry with me.")
+ ));
+ return;
+ }
+ select
+ l("Your mother is sorry about the roses. Here are some beautiful red tulips instead.");
+ mes "";
+ delitem ARedTulip, 15;
+ setq HurnscaldQuests_Rossy, 14;
+ quest_xp(.maxLevel, 2500);
+ quest_jxp(.maxLevel, 250);
+ mesn;
+ mesq l("That's better! Go and tell my mother that she is the nicest mother in the world.");
+ next;
+ mesn;
+ mesq l("However... Now I should really find my sister. Come back later.");
+ return;
+}
+
+function rossyJulietIntro {
+ if (BaseLevel < .minLevel_rescue) {
+ mesn;
+ mesq l("I think I have an idea where Juliet might be. Come back in a few levels, and I will tell you if she is ok.");
+ return;
+ }
+ mesn;
+ mesq l("%s, you have to help me! I saw Juliet, but something was wrong!!", strcharinfo(0));
+ next;
+ select
+ l("Calm down and tell me what happened.");
+ mes "";
+ mesn;
+ mesq l("No time for that! She was running away from something and entered a cave not far from here. I heard her scream. Please, can you enter the cave and save her? I'm so scared!");
+ next;
+ mesc l("%s is too distressed to be of any help. It might be a better idea to go inside the cave and look for Juliet.", .name$);
+ mesc l("The cave is %s", b(l("Northwest of here.")));
+ setq HurnscaldQuests_Rossy, 16;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+
+ // Quest conf
+ .blueberries_amount=30;
+ .minLevel_rescue = 60;
+ .maxLevel = 90;
+ end;
+}
diff --git a/npc/008-1/sabine.txt b/npc/008-1/sabine.txt
new file mode 100644
index 00000000..dc2b11b7
--- /dev/null
+++ b/npc/008-1/sabine.txt
@@ -0,0 +1,63 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-1,291,97,0 script Sabine NPC_SABINE,{
+
+ if (getq(.quest_inspector) != 2)
+ {
+ npctalk3(generic(1 | 16));
+ end;
+ }
+
+ speech(4,
+ l("Isn't this place pretty?"),
+ l("I love hanging out here!"));
+
+ selectd(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ speech(
+ l("No, sorry."));
+
+ close;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/sergeant-ryan.txt b/npc/008-1/sergeant-ryan.txt
new file mode 100644
index 00000000..975587e4
--- /dev/null
+++ b/npc/008-1/sergeant-ryan.txt
@@ -0,0 +1,71 @@
+// Evol scripts.
+// Author:
+// Livio
+// Description:
+// Save Sergeant Ryan
+
+008-1,55,47,0 script Sergeant Ryan NPC_RAIJIN_MALE_BROTHERHOOD,{
+function advanceQuest;
+function advanceQuest {
+ setq(General_CptHal, getq(General_CptHal) + 1);
+ return;
+}
+
+ if (getq(General_CptHal)<=3) {
+ speech
+ l("Aaah!!! Dammit!!!"),
+ l("It hurts like hell, #@%!!!!"),
+ l("Go away, my comrades will be here soon!");
+ }
+ if (getq(General_CptHal)==3) {
+ select l("No. They won't because Hal sent me to look after you, Tom Hanks.");
+ speech l("Aaah!!! What?");
+ select l("You are hurt! Looks like I have to save private Ryan...");
+ speech l("I'm a Sergeant. I could teach you a lesson or two if it wasn't for my leg.");
+ select l("Does it hurts if I touch here?");
+ speech l("@#@%&#@*!!!");
+ select l("This leg is badly hurt! Let me look out for something to heal it.");
+ speech l("Grr... I'm so nuts that I want to get even first with damn wolverns.");
+ speech l("Bring me:");
+ printIngredients(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ next;
+ advanceQuest();
+ close;
+ }
+ if (getq(General_CptHal)==4) {
+ if (checkForItems(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT)) {
+ speech l("Yeah, finally!!!");
+ next;
+ BaseExp += 15 * BaseLevel;
+ Zeny += 50;
+ advanceQuest();
+ delitem(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ speech l("Go tell Hal that I'm fine and I will go on with the mission as soon as possible.");
+ } else {
+ speech l("What are you doing here?!? I need:");
+ printIngredients(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ speech l("Come on, kill those bastards!!! Wolverns must pay the price of tasting my damn leg!!!");
+ select l("Fine. But PETA is not going to be happy about it...");
+ speech l("@#@%&#@*!!!");
+ }
+ close;
+ }
+ if (getq(General_CptHal)>=5) {
+ speech l("Thanks! Now move, I have a mission to accomplish.");
+ }
+ close;
+
+OnInit:
+ // NPC ITEM REQUESTS
+ setarray(.REQ0_INGREDIENTS,
+ WolvernPelt,
+ BottleOfWater
+ );
+ setarray(.REQ0_INGREDIENTS_AMOUNT,
+ 1,
+ 1
+ );
+
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/shop.txt b/npc/008-1/shop.txt
new file mode 100644
index 00000000..b2b4a406
--- /dev/null
+++ b/npc/008-1/shop.txt
@@ -0,0 +1,50 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Micksha
+// Reid
+// toams
+// Description:
+// Blossom flower shop.
+
+008-1,201,136,0 trader #Invisible008-1 NPC_HIDDEN,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem ARedRose, -1, 50;
+ sellitem AWhiteRose, -1, 50;
+ sellitem AYellowRose, -1, 50;
+ sellitem ABlueRose, -1, 20;
+ sellitem ARedTulip, -1, 50;
+ sellitem AWhiteTulip, -1, 50;
+ sellitem AYellowTulip, -1, 50;
+
+ .distance = 10;
+ end;
+
+OnClock0000:
+ restoreshopitem ARedRose, 10;
+ restoreshopitem AWhiteRose, 10;
+ restoreshopitem AYellowRose, 10;
+ restoreshopitem ABlueRose, 5;
+ restoreshopitem ARedTulip, 10;
+ restoreshopitem AWhiteTulip, 10;
+ restoreshopitem AYellowTulip, 10;
+OnClock0800:
+ restoreshopitem ARedRose, 10;
+ restoreshopitem AWhiteRose, 10;
+ restoreshopitem AYellowRose, 10;
+ restoreshopitem ABlueRose, 5;
+ restoreshopitem ARedTulip, 10;
+ restoreshopitem AWhiteTulip, 10;
+ restoreshopitem AYellowTulip, 10;
+OnClock1600:
+ restoreshopitem ARedRose, 10;
+ restoreshopitem AWhiteRose, 10;
+ restoreshopitem AYellowRose, 10;
+ restoreshopitem ABlueRose, 5;
+ restoreshopitem ARedTulip, 10;
+ restoreshopitem AWhiteTulip, 10;
+ restoreshopitem AYellowTulip, 10;
+}
diff --git a/npc/008-1/sign.txt b/npc/008-1/sign.txt
new file mode 100644
index 00000000..950fe996
--- /dev/null
+++ b/npc/008-1/sign.txt
@@ -0,0 +1,45 @@
+// Evol scripts.
+// Authors:
+// Micksha
+// Description:
+// Sign pillars in Hurnscald.
+
+008-1,142,105,0 script Sign#008-1-central NPC_NO_SPRITE,{
+ npctalkonce l("Right: Hurnscald | Down: Dimond's Cove | Left: West Woodland | Up: Nivalis (under construction)");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,126,160,0 script Sign#008-1-south NPC_NO_SPRITE,{
+ npctalkonce l("Down: Dimond's Cove | Left: Swamp");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,246,177,0 script Sign#008-1-southeast NPC_NO_SPRITE,{
+ npctalkonce l("Left: Dimond's Cove | Up: Hurnscald | Right: Forsaken Inn");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,251,104,0 script Sign#008-1-hurns NPC_NO_SPRITE,{
+ npctalkonce l("Left: West Woodland | Up: North Mine | Right: Harbor | Down: other directions");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,247,105,0 script Sign#008-1-4144 NPC_NO_SPRITE,{
+ npctalkonce l("This place is dedicated to 4144, the alltime Hero.");
+ close;
+OnInit:
+ .distance = 1;
+ end;
+}
diff --git a/npc/008-1/snarfles.txt b/npc/008-1/snarfles.txt
new file mode 100644
index 00000000..d4de8ed0
--- /dev/null
+++ b/npc/008-1/snarfles.txt
@@ -0,0 +1,97 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Snarfles the mouboo farmer.
+// THIS IS A PLACEHOLDER!
+
+008-1,79,118,0 script Snarfles NPC_SNARFLES,{
+ function foodQuest;
+ speech
+ l("My Mouboos, my beloved Mouboos!"),
+ l("Oh, hi, isn't it cool to live among all those Mouboos? I don't understand how some people can eat Mouboo steak."),
+ l("Murderers!");
+ if (getq(General_SmearedHands) <= 3 && getq2(General_SmearedHands) != 2)
+ foodQuest();
+ close;
+
+function foodQuest {
+ .@q=getq(General_SmearedHands);
+ next;
+ mesn;
+ mesq l("Ah... I could use some Asparagus with Hollondaise now...");
+ switch (.@q) {
+ case 1:
+ next;
+ mesn strcharinfo(0);
+ select
+ l("\"Asparagus with Hollondaise\"? What's that?"),
+ menuaction(l("Leave"));
+ mes "";
+ if (@menu == 2)
+ break;
+ mesn;
+ mesq l("Some call it %s, but it is so tasty...", getitemlink(VeggiePlate));
+ next;
+ mesn;
+ mesq l("I could even make one for you and give the recipe, but...");
+ next;
+ mesn;
+ mesq l("I always get smeared hands eating it and cannot play cards anymore with Crane.");
+ next;
+ mesn;
+ mesq l("Well, if you find me a solution for that problem, I can give you the recipe. What do you say?");
+ next;
+ mesc l("WARNING: If you accept this quest, you'll be struck at the %s route!", b(l("Vegetarian"))), 1;
+ mesc l("This will also make %s's Quest unavailable.", b("Crane")), 1;
+ mesc l("This decision cannot be changed later."), 1;
+ next;
+ mesc l("Accept this request?"), 1;
+ if (askyesno() == ASK_YES) {
+ setq General_SmearedHands, 2, VEGAN; // 1 = Vegan
+ mesn;
+ mesq l("Great! I'll be eager for your return!");
+ }
+ break;
+ case 2:
+ mesn;
+ mesq l("Have you found a solution for my smeared hands problem?");
+ next;
+ select
+ l("No, not yet.");
+ mes "";
+ mesn;
+ mesq l("I've heard they're related to the earl of sandwich, so maybe a sandwich maker could help... *sigh* I want to play cards...");
+ break;
+ case 3:
+ mesn strcharinfo(0);
+ select
+ l("Have you tried putting it in a bread already?"),
+ l("I'll keep looking for solutions for your problem.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("Actually... No. Have been too afraid of it tasting foul.");
+ next;
+ mesn strcharinfo(0);
+ mesq l("Really? Tiki, Candor's chef, liked it very much.");
+ next;
+ mesn;
+ mesq l("Wha - Really?! Tiki said it tasted good??! I'm saved! You're truly my savior!!");
+ next;
+ mesn;
+ mesq l("I'll put the %s recipe on your %s. Thanks, you saved my day!", getitemlink(VeggiePlate), getitemlink(RecipeBook));
+ RECIPES[CraftVeggiePlate]=true;
+ getitembound VeggiePlate, 1, IBT_ACCOUNT;
+ setq1 General_SmearedHands, 4; // Finished
+ default:
+ return;
+ }
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/soul-menhir.txt b/npc/008-1/soul-menhir.txt
new file mode 100644
index 00000000..61112de5
--- /dev/null
+++ b/npc/008-1/soul-menhir.txt
@@ -0,0 +1,9 @@
+// The Mana World scripts.
+// Author:
+// gumi
+// Jesusalva
+// Description:
+// place of power, mana refills faster when sitting nearby
+
+008-1,252,111,0 duplicate(Soul Menhir) Soul Menhir#hurn_1_7_200 NPC_NO_SPRITE
+
diff --git a/npc/008-1/voltain.txt b/npc/008-1/voltain.txt
new file mode 100644
index 00000000..ce41f10b
--- /dev/null
+++ b/npc/008-1/voltain.txt
@@ -0,0 +1,18 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Voltain the dark druid.
+// THIS IS A PLACEHOLDER!
+
+008-1,182,155,0 script Voltain NPC_DARK_DRUID,{
+ speech
+ l("Go away, I have to think about new evil doings."),
+ l("GO AWAY, I SAID!");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/wateranimation.txt b/npc/008-1/wateranimation.txt
new file mode 100644
index 00000000..ce72d893
--- /dev/null
+++ b/npc/008-1/wateranimation.txt
@@ -0,0 +1,21 @@
+// The Mana World scripts.
+// Description:
+// Water animations, splash, fishes, etc...
+
+008-1,90,223,0 duplicate(#fish_river) #hurns_fish01 NPC_WATER_SPLASH
+008-1,86,177,0 duplicate(#fish_river) #hurns_fish02 NPC_WATER_SPLASH
+008-1,85,186,0 duplicate(#fish_river) #hurns_fish03 NPC_WATER_SPLASH
+008-1,89,208,0 duplicate(#fish_river) #hurns_fish04 NPC_WATER_SPLASH
+008-1,139,91,0 duplicate(#fish_river) #hurns_fish05 NPC_WATER_SPLASH
+008-1,64,36,0 duplicate(#fish_river) #hurns_fish06 NPC_WATER_SPLASH
+008-1,55,30,0 duplicate(#fish_river) #hurns_fish07 NPC_WATER_SPLASH
+008-1,46,35,0 duplicate(#fish_river) #hurns_fish08 NPC_WATER_SPLASH
+008-1,105,55,0 duplicate(#fish_river) #hurns_fish09 NPC_WATER_SPLASH
+008-1,214,155,0 duplicate(#fish_river) #hurns_fish10 NPC_WATER_SPLASH
+008-1,216,153,0 duplicate(#fish_river) #hurns_fish11 NPC_WATER_SPLASH
+008-1,225,26,0 duplicate(#fish_river) #hurns_fish12 NPC_WATER_SPLASH
+008-1,220,49,0 duplicate(#fish_river) #hurns_fish13 NPC_WATER_SPLASH
+008-1,220,57,0 duplicate(#fish_river) #hurns_fish14 NPC_WATER_SPLASH
+008-1,233,56,0 duplicate(#fish_river) #hurns_fish15 NPC_WATER_SPLASH
+008-1,230,51,0 duplicate(#fish_river) #hurns_fish16 NPC_WATER_SPLASH
+
diff --git a/npc/008-2-0/_import.txt b/npc/008-2-0/_import.txt
new file mode 100644
index 00000000..2cd1023b
--- /dev/null
+++ b/npc/008-2-0/_import.txt
@@ -0,0 +1,6 @@
+// Map 008-2-0: Chez Celestia
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-0/_savepoints.txt",
+"npc/008-2-0/_warps.txt",
+"npc/008-2-0/celestia.txt",
+"npc/008-2-0/mapflags.txt",
diff --git a/npc/008-2-0/_savepoints.txt b/npc/008-2-0/_savepoints.txt
new file mode 100644
index 00000000..2c108fa8
--- /dev/null
+++ b/npc/008-2-0/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-0: Chez Celestia saves
+008-2-0,38,27,0 script #save_008-2-0_38_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-0/_warps.txt b/npc/008-2-0/_warps.txt
new file mode 100644
index 00000000..d24b4b27
--- /dev/null
+++ b/npc/008-2-0/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-0: Chez Celestia warps
+008-2-0,26,22,0 warp #008-2-0_26_22 0,0,008-1,276,121
+008-2-0,22,34,0 warp #008-2-0_22_34 0,0,008-1,273,125
diff --git a/npc/008-2-0/celestia.txt b/npc/008-2-0/celestia.txt
new file mode 100644
index 00000000..81fb372b
--- /dev/null
+++ b/npc/008-2-0/celestia.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Our beloved Princess Celestia.
+// THIS IS A PLACEHOLDER!
+
+008-2-0,30,23,0 script Celestia NPC_CELESTIA,{
+ speech
+ l("Hi!"),
+ l("You may remember me, I am Celestia.");
+ l("Take a cup of tea until something happens here.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-0/mapflags.txt b/npc/008-2-0/mapflags.txt
new file mode 100644
index 00000000..93df75f4
--- /dev/null
+++ b/npc/008-2-0/mapflags.txt
@@ -0,0 +1 @@
+008-2-0 mapflag town
diff --git a/npc/008-2-1/_import.txt b/npc/008-2-1/_import.txt
new file mode 100644
index 00000000..06ba6d3b
--- /dev/null
+++ b/npc/008-2-1/_import.txt
@@ -0,0 +1,9 @@
+// Map 008-2-1: Merchant Guild
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-1/_savepoints.txt",
+"npc/008-2-1/_warps.txt",
+"npc/008-2-1/generalstore.txt",
+"npc/008-2-1/inspector.txt",
+"npc/008-2-1/mapflags.txt",
+"npc/008-2-1/richard.txt",
+"npc/008-2-1/selim.txt",
diff --git a/npc/008-2-1/_savepoints.txt b/npc/008-2-1/_savepoints.txt
new file mode 100644
index 00000000..19f0f307
--- /dev/null
+++ b/npc/008-2-1/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-1: Merchant Guild saves
+008-2-1,42,27,0 script #save_008-2-1_42_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-1/_warps.txt b/npc/008-2-1/_warps.txt
new file mode 100644
index 00000000..978c5767
--- /dev/null
+++ b/npc/008-2-1/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-1: Merchant Guild warps
+008-2-1,37,27,0 warp #008-2-1_37_27 0,0,008-1,260,111
+008-2-1,33,45,0 warp #008-2-1_33_45 0,0,008-1,259,119
diff --git a/npc/008-2-1/generalstore.txt b/npc/008-2-1/generalstore.txt
new file mode 100644
index 00000000..ffbbb6d1
--- /dev/null
+++ b/npc/008-2-1/generalstore.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// General Store.
+// THIS IS A PLACEHOLDER!
+
+008-2-1,38,35,0 script General Store#008-1 NPC_GENERAL_STORE,{
+ speech
+ l("Hi!"),
+ l("My name is General Store, they still call me this although I left the army a few years ago."),
+ l("I have nothing to sell, come back later.");
+
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/008-2-1/inspector.txt b/npc/008-2-1/inspector.txt
new file mode 100644
index 00000000..6d7915d5
--- /dev/null
+++ b/npc/008-2-1/inspector.txt
@@ -0,0 +1,190 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-2-1,30,34,0 script Inspector NPC_INSPECTOR,{
+
+ if (BaseLevel < .min_level)
+ {
+ npctalk3(l("I'm sorry, but I'm busy looking into this string of robberies."));
+ end;
+ }
+
+ // OnTalk:
+ switch (getq(.quest))
+ {
+ case 0:
+ case 1:
+ speech(4,
+ l("Hmm... what to do."));
+ narrator(4,
+ l("He looks up and into your face."));
+ speech(4,
+ l("You look capable, will you help me solve these robberies?"),
+ l("I would go myself, but for some reason I'm a non-walking NPC."));
+
+ if (selectd("Yes", "No") == 2) {
+ closeclientdialog();
+ close;
+ }
+
+ speech(
+ l("Ok then."),
+ l("I'd like you to ask the villagers about the recent string of robberies."));
+
+ close2;
+ setq(.quest, 2);
+ end;
+
+ case 2:
+ npctalk3(l("Please continue talking to the villagers."));
+ end;
+
+ case 3:
+ speech(
+ l("Hm..."),
+ l("I don't know if I trust her eyesight or memory."),
+ l("See if someone else knows anything."));
+ close;
+
+ case 4:
+ speech(
+ l("Someone in a theater mask, eh?"),
+ l("There was a traveling theater troupe in town recently, but they've moved on to Tulimshar."),
+ l("Please go talk to their leader about this."));
+
+ close2;
+ setq(.quest, 5);
+ end;
+
+ case 5:
+ npctalk3(l("Please go talk to the leader of the traveling troupe about the theater mask."));
+ end;
+
+ case 6:
+ speech(
+ l("Hm... an old man?"),
+ l("Could you interrogate him for me?"));
+
+ close2;
+ setq(.quest, 7);
+ end;
+
+ case 7:
+ npctalk3(l("Have you talked with the old man yet?"));
+ end;
+
+ case 8:
+ npctalk3(l("Can you verify that with his wife?"));
+ end;
+
+ case 9:
+ speech(
+ l("Hm... then it couldn't be him."),
+ l("I'm not sure where to go from here, maybe you can find something else."),
+ l("Try talking to everyone again."));
+
+ close2;
+ setq(.quest, 10);
+ end;
+
+ case 10:
+ npctalk3(l("Made any progress yet?"));
+ end;
+
+ case 11:
+ npctalk3(l("Then go north and investigate!"));
+ end;
+
+ case 12:
+ npctalk3(l("Did you look over the basement?"));
+ end;
+
+ case 13:
+ speech(
+ l("What a strange note."),
+ l("I'll keep track of this, while you return the mask to the troupe."),
+ l("I would go myself, but the developers were too lazy to make me walk."),
+ "...",
+ l("By the way, stay sharp! I may call upon you again."));
+
+ close2;
+ setq(.quest, 14);
+ end;
+
+ case 14:
+ npctalk3(l("Please return the mask to the traveling troupe."));
+ end;
+
+ case 15:
+ speech(
+ l("My men have found all of the stolen items."),
+ l("They were all in the mining camp."),
+ l("We still don't know who did it.")); // XXX: feel free to extend this quest beyond this point
+
+ close2;
+ setq(.quest, 16);
+ quest_xp(.maxLevel, .reward_exp);
+ end;
+
+ case 16:
+ npctalk3(l("Remember to stay sharp. I might need your help on another case."));
+ end;
+ }
+
+ closeclientdialog();
+ close;
+
+OnPCLoginEvent:
+OnPCBaseLvUpEvent:
+ if (BaseLevel >= .min_level && getq(.quest) < 1)
+ {
+ setq(.quest, 1); // allow the player to do the quest
+ dispbottom(l("New quest available: %s (level %d+)",
+ getquestlink(.quest), .min_level)); // XXX: requires new manaplus versions, maybe show a different message for old versions?
+ }
+ end;
+
+OnInit:
+ .min_level = 30; // min level to do the quest
+ .maxLevel = 60;
+
+ .reward_exp = 2500;
+
+ .quest = HurnscaldQuests_Inspector;
+ .quest_debug = .quest;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-2-1/mapflags.txt b/npc/008-2-1/mapflags.txt
new file mode 100644
index 00000000..78899489
--- /dev/null
+++ b/npc/008-2-1/mapflags.txt
@@ -0,0 +1 @@
+008-2-1 mapflag town
diff --git a/npc/008-2-1/richard.txt b/npc/008-2-1/richard.txt
new file mode 100644
index 00000000..d55ade4f
--- /dev/null
+++ b/npc/008-2-1/richard.txt
@@ -0,0 +1,62 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Richard the Hurns storage guy.
+// THIS IS A PLACEHOLDER!
+
+008-2-1,26,35,0 script Richard NPC_RICHARD_LEGACY,{
+ // Storage/Banking function not unlocked in Artis
+ if (!getq(ArtisQuests_Lloyd)) {
+ speech
+ l("Oh hey!"),
+ l("I was supposed to act as storagekeeper, but I forgot my key."),
+ l("Come back later, perhaps I can find it.");
+ close;
+ }
+ mesn;
+ mesq l("Welcome to %s's Bank!", l($@BANK_TOWN$[.bankid]));
+ next;
+
+ do
+ {
+ select
+ l("I would like to store some items."),
+ l("I would like to perform money transactions."),
+ l("Is there any request for me?"),
+ menuaction(l("Quit"));
+
+ mes "";
+
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("Sure thing! I'll have your items transported here from Artis before you realize!");
+ next;
+ closeclientdialog();
+ openstorage();
+ close;
+ case 2:
+ MerchantGuild_Bank();
+ break;
+ case 3:
+ MerchantGuild_Quests(.bankid);
+ break;
+ default:
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ } while (true);
+ close;
+
+OnInit:
+ .distance = 4;
+
+ // Bank configuration
+ array_push($@BANK_NAME$, .name$);
+ array_push($@BANK_TOWN$, "Hurnscald");
+ .bankid = getarraysize($@BANK_NAME$)-1;
+ end;
+}
diff --git a/npc/008-2-1/selim.txt b/npc/008-2-1/selim.txt
new file mode 100644
index 00000000..7e947890
--- /dev/null
+++ b/npc/008-2-1/selim.txt
@@ -0,0 +1,22 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Selim the Dyer.
+// THIS IS A PLACEHOLDER!
+
+008-2-1,38,40,0 script Selim NPC_GUMI_THE_DYER,{
+ speech
+ l("Oh hey!"),
+ l("Good you are here, you could be handy for me right now."),
+ l("Or maybe later. Hmm, we'll see."),
+ l("On the meanwhile...");
+
+ Barber(false);
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-10/_import.txt b/npc/008-2-10/_import.txt
new file mode 100644
index 00000000..2dd9ec77
--- /dev/null
+++ b/npc/008-2-10/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-10: Hurnscald City Hall
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-10/_warps.txt",
+"npc/008-2-10/airlia.txt",
+"npc/008-2-10/mapflags.txt",
diff --git a/npc/008-2-10/_warps.txt b/npc/008-2-10/_warps.txt
new file mode 100644
index 00000000..26362dee
--- /dev/null
+++ b/npc/008-2-10/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-10: Hurnscald City Hall warps
+008-2-10,37,34,0 warp #008-2-10_37_34 0,0,008-1,273,117
+008-2-10,36,25,0 warp #008-2-10_36_25 2,0,008-2-11,36,27
diff --git a/npc/008-2-10/airlia.txt b/npc/008-2-10/airlia.txt
new file mode 100644
index 00000000..64f18436
--- /dev/null
+++ b/npc/008-2-10/airlia.txt
@@ -0,0 +1,33 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Airlia, the major's daughter.
+// THIS IS A PLACEHOLDER!
+
+008-2-10,42,29,0 script Airlia NPC_AIRLIA,{
+ speech
+ l("Hello."),
+ l("Do you know where the graveyard is?"),
+ l("No? Better that way. It's so dangerous there.");
+
+ if (getq(General_Brotherhood) < 2)
+ close;
+ next;
+ select
+ l("Okay, thanks."),
+ l("*whisper* Sagratha is great.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Ah, uhm, erm. The Governor is busy arguing with the rest of the team.");
+ next;
+ mesn;
+ mesq l("I'm afraid you'll need to wait them to reach a consensus first, before he can met with you.");
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-10/mapflags.txt b/npc/008-2-10/mapflags.txt
new file mode 100644
index 00000000..7635bed5
--- /dev/null
+++ b/npc/008-2-10/mapflags.txt
@@ -0,0 +1 @@
+008-2-10 mapflag town
diff --git a/npc/008-2-11/_import.txt b/npc/008-2-11/_import.txt
new file mode 100644
index 00000000..84ad9ceb
--- /dev/null
+++ b/npc/008-2-11/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-11: Hurnscald City Hall
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-11/_savepoints.txt",
+"npc/008-2-11/_warps.txt",
+"npc/008-2-11/mapflags.txt",
diff --git a/npc/008-2-11/_savepoints.txt b/npc/008-2-11/_savepoints.txt
new file mode 100644
index 00000000..db593899
--- /dev/null
+++ b/npc/008-2-11/_savepoints.txt
@@ -0,0 +1,28 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-11: Hurnscald City Hall saves
+008-2-11,26,27,0 script #save_008-2-11_26_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-11,45,27,0 script #save_008-2-11_45_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-11/_warps.txt b/npc/008-2-11/_warps.txt
new file mode 100644
index 00000000..11b8b45f
--- /dev/null
+++ b/npc/008-2-11/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-11: Hurnscald City Hall warps
+008-2-11,36,31,0 warp #008-2-11_36_31 2,0,008-2-10,36,26
diff --git a/npc/008-2-11/mapflags.txt b/npc/008-2-11/mapflags.txt
new file mode 100644
index 00000000..3e084fc0
--- /dev/null
+++ b/npc/008-2-11/mapflags.txt
@@ -0,0 +1 @@
+008-2-11 mapflag town
diff --git a/npc/008-2-12/_import.txt b/npc/008-2-12/_import.txt
new file mode 100644
index 00000000..f5f593a2
--- /dev/null
+++ b/npc/008-2-12/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-12: Hurnscald Clinic
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-12/_warps.txt",
+"npc/008-2-12/mapflags.txt",
+"npc/008-2-12/nurse.txt",
diff --git a/npc/008-2-12/_warps.txt b/npc/008-2-12/_warps.txt
new file mode 100644
index 00000000..efe934a0
--- /dev/null
+++ b/npc/008-2-12/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-12: Hurnscald Clinic warps
+008-2-12,30,32,0 warp #008-2-12_30_32 0,0,008-1,281,104
+008-2-12,36,27,0 warp #008-2-12_36_27 1,0,008-2-13,35,30
diff --git a/npc/008-2-12/mapflags.txt b/npc/008-2-12/mapflags.txt
new file mode 100644
index 00000000..b52526a7
--- /dev/null
+++ b/npc/008-2-12/mapflags.txt
@@ -0,0 +1 @@
+008-2-12 mapflag town
diff --git a/npc/008-2-12/nurse.txt b/npc/008-2-12/nurse.txt
new file mode 100644
index 00000000..415746cf
--- /dev/null
+++ b/npc/008-2-12/nurse.txt
@@ -0,0 +1,175 @@
+// Evol scripts.
+// Author:
+// gumi
+// The Moubootaur Legends Development Team
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// Hurnscald Nurse. Robberies in Hurnscald.
+
+008-2-12,28,30,0 script Nurse NPC_NURSE_LEGACY,{
+ function bloodDonor;
+ .@q2=getq2(HurnscaldQuests_BloodDonor);
+
+ speech(4,
+ l("How can I help you?"));
+
+ // XXX: this npc used to teach the resist poison skill, do we still want that?
+
+ selectd(
+ l("Oooh, these wounds! They hurt so much!"),
+ l("I don't feel so well, I might be sick."),
+ rif(.@q2 < gettimetick(2), l("I would like to donate blood.")),
+ l("No, I'm fine."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything out of the ordinary?")));
+
+ switch (@menu)
+ {
+ case 1:
+ if (BaseLevel > .heal_max_level)
+ {
+ speech(
+ l("I'm sorry but I'm here only to help young adventurers and the town residents."),
+ l("Your level is already higher than %d.", .heal_max_level),
+ l("You can get some rest at the inn near here."));
+ close;
+ }
+ speech(4,
+ l("Here, let me heal you."));
+
+ // Jesusalva: I don't trust npcskill()
+ npcskill(AL_HEAL, .heal_skill_level, .heal_npc_stats, .heal_npc_level);
+
+ speech(
+ l("There you go, like new."));
+ break;
+ case 2:
+ speech(
+ l("Then you should better see the doctor."),
+ l("He is usually in his office on the 3rd floor."));
+ break;
+ case 3:
+ bloodDonor();
+ break;
+ case 4:
+ speech(
+ l("Then I would ask you to leave."),
+ l("There are people who really need our help."));
+ break;
+ case 5:
+ speech(
+ l("I'm too busy here to observe the town."));
+ break;
+ }
+ close;
+
+function bloodDonor {
+ .@q2=getq2(HurnscaldQuests_BloodDonor);
+ .@q3=getq3(HurnscaldQuests_BloodDonor);
+ // Cheating??!
+ if (.@q2 > gettimetick(2))
+ kick(getcharid(3));
+ // Anyway, ML code comes here, adapted for TMW
+ mesc l("Donating blood will BLOCK YOUR MOVEMENT for three minutes.");
+ mesc l("Do not disconnect while waiting. You need 100% HP to donate.");
+ next;
+ // Always show Info if it is your first time donating blood
+ @menu = 1;
+ if (.@q3) {
+ select
+ l("Info"),
+ rif(readparam(Hp) == readparam(MaxHp), l("Yes, please use my blood to save lifes.")),
+ l("I changed my mind");
+ mes "";
+ }
+ if (@menu == 3)
+ return;
+ if (@menu == 1) {
+ mesn;
+ mesq l("Donating blood is a noble act, which allows to save lifes.");
+ next;
+ mesn;
+ mesq l("When people loses too much blood, they die, unless we can lend them somebody's else blood.");
+ next;
+ mesn;
+ mesq l("Not everyone can be a blood donor. For example, you must be healthy.");
+ mesq l("You can find more info about this on these links:");
+ mes "";
+ mes "[@@https://www.blood.co.uk/|https://www.blood.co.uk/@@]";
+ mes "[@@https://www.nhsbt.nhs.uk/what-we-do/blood-services/blood-donation/|https://www.nhsbt.nhs.uk/what-we-do/blood-services/blood-donation/@@]";
+ mes l("France: [@@https://dondesang.efs.sante.fr/|https://dondesang.efs.sante.fr/@@]");
+ mes l("Brazil: [@@http://www.prosangue.sp.gov.br/home/Default.html|http://www.prosangue.sp.gov.br/home/Default.html@@]");
+ if (readparam(Hp) < readparam(MaxHp))
+ return;
+ next;
+ mesc l("Donate blood?", 1);
+ if (askyesno() == ASK_NO)
+ return;
+ }
+ // Donate blood
+ mesn;
+ mesq l("This will take only a short while.");
+ next;
+ setq1 HurnscaldQuests_BloodDonor, 2;
+ percentheal -90, 0;
+ addtimer(180000, "Nurse::OnDonationComplete");
+ warp "008-2-14", 31, 27;
+ setpcblock(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM|PCBLOCK_MOVE, true);
+ dispbottom l("Any movement/skill/item will be without effect until time is up.");
+ closedialog;
+ return;
+}
+
+OnDonationComplete:
+ if (checkpcblock() & PCBLOCK_ATTACK)
+ setpcblock(PCBLOCK_ATTACK|PCBLOCK_SKILL|PCBLOCK_USEITEM|PCBLOCK_MOVE, false);
+ warp "008-2-12", 30, 30;
+ percentheal 100, 0;
+ // Experience gain is based on HP
+ getexp readparam(Hp)*2, readparam(Hp)/100;
+ .@q3=getq3(HurnscaldQuests_BloodDonor)+1;
+ // Cooldown: 60*60*24*30: 30 days
+ setq HurnscaldQuests_BloodDonor, 1, gettimetick(2)+(2592000), .@q3;
+ if (BaseLevel >= 30)
+ getitem Bread, 1;
+ if (BaseLevel >= 50)
+ getitem ChocolateBar, 1;
+ if (BaseLevel >= 70)
+ getitem BottleOfWater, 1;
+ mesn;
+ mesq l("Thanks for donating blood. You can donate again in 30 days.");
+ mesq l("You should eat and drink water after donating blood. Thanks for saving lifes!");
+ close;
+
+
+OnInit:
+ .heal_max_level = 20; // she will only heal low level players
+
+ .heal_skill_level = 10; // what level of the healing skill to use
+ .heal_npc_stats = 99; // what stat points the NPC has
+ .heal_npc_level = 60; // what level the npc has
+
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 3;
+ end;
+}
diff --git a/npc/008-2-13/_import.txt b/npc/008-2-13/_import.txt
new file mode 100644
index 00000000..ec6a73b7
--- /dev/null
+++ b/npc/008-2-13/_import.txt
@@ -0,0 +1,6 @@
+// Map 008-2-13: Hurnscald Clinic
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-13/_savepoints.txt",
+"npc/008-2-13/_warps.txt",
+"npc/008-2-13/lena.txt",
+"npc/008-2-13/mapflags.txt",
diff --git a/npc/008-2-13/_savepoints.txt b/npc/008-2-13/_savepoints.txt
new file mode 100644
index 00000000..b82ce152
--- /dev/null
+++ b/npc/008-2-13/_savepoints.txt
@@ -0,0 +1,54 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-13: Hurnscald Clinic saves
+008-2-13,29,27,0 script #save_008-2-13_29_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-13,32,27,0 script #save_008-2-13_32_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-13,29,31,0 script #save_008-2-13_29_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-13,32,31,0 script #save_008-2-13_32_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-13/_warps.txt b/npc/008-2-13/_warps.txt
new file mode 100644
index 00000000..cba843a7
--- /dev/null
+++ b/npc/008-2-13/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-13: Hurnscald Clinic warps
+008-2-13,36,32,0 warp #008-2-13_36_32 1,0,008-2-12,35,29
+008-2-13,25,26,0 warp #008-2-13_25_26 1,0,008-2-14,24,30
diff --git a/npc/008-2-13/lena.txt b/npc/008-2-13/lena.txt
new file mode 100644
index 00000000..1de7a98b
--- /dev/null
+++ b/npc/008-2-13/lena.txt
@@ -0,0 +1,270 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// Lena the Bowwoman.
+
+008-2-13,27,27,0 script Lena NPC_LENA,{
+ .@q=getq(HurnscaldQuest_Bandits);
+ // Declare all functions
+ // Stage 1
+ function lenaTooWeak;
+ function lenaStart;
+ function lenaReturn;
+ // Stage 2
+ function lenaQuest;
+ function lenaCoinBag;
+ // Stage 3
+ function lenaBusy;
+ function lenaBusy2;
+ function lenaBanditLord;
+ function lenaFinish;
+ // Post stage
+ function lenaDaily;
+
+ switch (.@q) {
+ // Stage 1
+ case 0:
+ if (BaseLevel < .minLevel_1)
+ lenaTooWeak();
+ lenaStart();
+ break;
+ case 1:
+ lenaReturn();
+ break;
+ // Stage 2
+ case 2:
+ if (BaseLevel < .minLevel_2)
+ lenaTooWeak();
+ lenaQuest();
+ break;
+ case 3:
+ lenaCoinBag();
+ break;
+ // Stage 3
+ case 4:
+ if (BaseLevel < .minLevel_1)
+ lenaBusy();
+ lenaBanditLord();
+ break;
+ case 5:
+ case 6:
+ lenaBusy2();
+ break;
+ case 7:
+ lenaFinish();
+ break;
+ }
+ close;
+
+function lenaDaily {
+ // DailyQuest(lvl, cost, count, item)
+ DailyQuest(40, 4, 10, CoinBag);
+ return;
+}
+
+// ------------------------------------
+function lenaTooWeak {
+ speech
+ l("Hey."),
+ l("Did you hear about the Bandit's attacks? They must have a hideout somewhere outside Hurnscald."),
+ l("However, you are too weak to help me, so come back later.");
+ close;
+}
+
+function lenaBusy {
+ speech
+ l("Hey."),
+ l("Ah, I wish my dear friend Nickos could be here. He's one of the guards in Tulimshar and he'd know how to deal with those outlaws!"),
+ l("I will inform you when I have more information about the bandits.");
+ close;
+}
+
+function lenaBusy2 {
+ mesn;
+ mesq l("%s, we are counting on you! We, the whole Hurnscald town!", strcharinfo(0));
+ close;
+}
+
+// ------------------------------------ Stage 1
+function lenaStart {
+ mesn;
+ mesq l("Ah, hello.");
+ next;
+ mesn;
+ mesq l("We actually have a problem. Bandits ransacked Hurnscald, and took a huge loot.");
+ next;
+ mesn;
+ mesq l("We pursued them until the mines, slayed them, and took the chests where they locked our stuff into.");
+ next;
+ mesn;
+ mesq l("The problem is... The slimes ate the keys for the chests. This is not the first time such thing happens.");
+ next;
+ mesn;
+ mesq l("If you bring us %d %s, we'll be forever grateful.", .numKeys, getitemlink(TreasureKey));
+ select
+ l("Don't worry ma'm, I'll recover the Treasure Keys at once."),
+ l("Ah... Slimes... Sorry, not my cup of tea...");
+ mes "";
+ if (@menu == 2)
+ close;
+ setq HurnscaldQuest_Bandits, 1;
+ mesn;
+ mesq l("Wonderful! I'll be expecting you back.");
+ return;
+}
+
+function lenaReturn {
+ mesn;
+ mesq l("Adventurer, did you brought me what I asked? I see you have %d/%d %s.", countitem(TreasureKey), .numKeys, getitemlink(TreasureKey));
+ mes "";
+ select
+ rif(countitem(TreasureKey) >= .numKeys, l("Yes, take it.")),
+ rif(countitem(TreasureKey) < .numKeys, l("No, I'll be back with them.")),
+ l("Hm, can we talk again later?");
+ mes "";
+ if (@menu != 1)
+ close;
+ delitem TreasureKey, .numKeys;
+ quest_gp(.maxLevel_1, 1000);
+ quest_xp(.maxLevel_1, 1599); // 20% from needed exp
+ setq HurnscaldQuest_Bandits, 2;
+ mesn;
+ mesq l("Hey hey... Good job! We can now use again the stuff we recovered from the bandits.");
+ next;
+ mesn;
+ mesq l("Here is some GP for your efforts. Thanks for making Hurnscald a better place to live.");
+ next;
+ mesn;
+ mesq l("This happens quite often, too. My friends and I are always collecting keys to reduce beer price on Hurnscald. %%2");
+ return;
+}
+
+// ------------------------------------ Stage 2
+function lenaQuest {
+ mesn;
+ mesq l("Ah, %s, good thing you are here.", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("Bandits are a huge threat to Hurnscald. We're just a small farming town, and they're countless.");
+ next;
+ mesn;
+ mesq l("Unlike the thieves guild, they are ruthless, and break everything. We lose more repairing damage than actually stolen.");
+ next;
+ mesn;
+ mesq l("Last time I went to fight the Bandit Lord, I was severely wounded.");
+ next;
+ mesn;
+ mesq l("I will reward whoever kills the current bandit leader, of course.");
+ select
+ l("I would gladly aid you to get rid of that scourge."),
+ l("Sorry, I forgot my courage on my other set of pants.");
+ mes "";
+ if (@menu == 2)
+ close;
+ setq HurnscaldQuest_Bandits, 3;
+ mesn;
+ mesq l("Wonderful! So, how about a warm up?");
+ next;
+ mesn;
+ mesq l("Bring me %d %s. This should help us amending the damage they caused and is a good warm-up exercise.", .numCoins, getitemlink(CoinBag));
+ return;
+}
+
+function lenaCoinBag {
+ mesn;
+ mesq l("Adventurer, did you brought me what I asked? I see you have %d/%d %s.", countitem(CoinBag), .numCoins, getitemlink(CoinBag));
+ mes "";
+ select
+ rif(countitem(CoinBag) >= .numCoins, l("Yes, take it.")),
+ rif(countitem(CoinBag) < .numCoins, l("No, I'll be back with them.")),
+ l("Hm, can we talk again later?");
+ mes "";
+ if (@menu != 1)
+ close;
+ inventoryplace FairyHat, 1;
+ delitem CoinBag, .numCoins;
+ .@gp=getiteminfo(CoinBag, ITEMINFO_SELLPRICE) * .numCoins * 15 / 10;
+ quest_gp(.maxLevel_2, .@gp); // +50% of base sell price
+ quest_xp(.maxLevel_2, 6842); // 20% from needed exp
+ getitem FairyHat, 1;
+ setq HurnscaldQuest_Bandits, 4;
+ mesn;
+ mesq l("Hey hey... Good job! This help us more than you think. Here is a hat like mine.");
+ next;
+ mesn;
+ mesq l("Unfortunately, I feel this bandit threat may have grown. Come back later, I'll talk with the Brotherhood for a while and probably will need your help again.");
+ return;
+}
+// ------------------------------------ Stage 3
+function lenaBanditLord {
+ mesn;
+ mesq l("So... I won't say you can't do it, %s. I will just say killing the Bandit Lord is no easy task.", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("The %s is not only a fearsome and ruthless leader. He is strong, and he have tricks on his sleeve.", getmonsterlink(BanditLord));
+ next;
+ mesn;
+ mesq l("He will summon allies if he think you have the upper hand. So take care if you are going ranged.");
+ next;
+ mesn;
+ mesq l("I know another Bandit Lord will take up his place, but the loss of their leader will make bandits scatter long enough.");
+ next;
+ mesn;
+ mesq l("Will you help me- no, I mean, will you help us, the whole town of Hurnscald?");
+ next;
+ select
+ l("Sorry, I need to better prepare myself."),
+ l("I would gladly give my life for such noble goal.");
+ mes "";
+ if (@menu == 1)
+ close;
+ setq HurnscaldQuest_Bandits, 5;
+ mesn;
+ mesq l("...You have courage. Many people tried and failed.");
+ next;
+ mesn;
+ mesq l("I know where the Bandit Lord room is, and I have a guard stationed not far from there. Ask him for the key.");
+ next;
+ mesn;
+ mesq l("One last thing... Good luck. This bandit threat needs to be pushed back.");
+ return;
+}
+
+function lenaFinish {
+ mesn;
+ mesq l("Ah... You did it!");
+ next;
+ mesn;
+ mesq l("That's easy to know, because the bandits are less coordinated. Perhaps we will be able to sleep in peace this night!");
+ next;
+ inventoryplace ForestArmor, 1;
+ getitem ForestArmor, 1;
+ quest_xp(.maxLevel_3, 5842); // 10% from needed exp
+ quest_jxp(.maxLevel_3, 93); // + JExp level 6
+ setq HurnscaldQuest_Bandits, 8;
+ mesn;
+ mesq l("Here is the %s, like my armor, and one of the best for rangers.", getitemlink(ForestArmor));
+ next;
+ mesn;
+ mesq l("Any friend of Hurnscald is my friend too. Come to me again, if you want to do daily quests!");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+
+ // Quest configuration
+ .minLevel_1=15;
+ .maxLevel_1=35;
+ .numKeys = 15;
+
+ .minLevel_2=30;
+ .maxLevel_2=50;
+ .numCoins = 20;
+
+ .minLevel_3=35;
+ .maxLevel_3=55;
+ end;
+}
diff --git a/npc/008-2-13/mapflags.txt b/npc/008-2-13/mapflags.txt
new file mode 100644
index 00000000..be0ed6a2
--- /dev/null
+++ b/npc/008-2-13/mapflags.txt
@@ -0,0 +1 @@
+008-2-13 mapflag town
diff --git a/npc/008-2-14/_import.txt b/npc/008-2-14/_import.txt
new file mode 100644
index 00000000..818ced88
--- /dev/null
+++ b/npc/008-2-14/_import.txt
@@ -0,0 +1,6 @@
+// Map 008-2-14: Hurnscald Clinic
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-14/_savepoints.txt",
+"npc/008-2-14/_warps.txt",
+"npc/008-2-14/doctor.txt",
+"npc/008-2-14/mapflags.txt",
diff --git a/npc/008-2-14/_savepoints.txt b/npc/008-2-14/_savepoints.txt
new file mode 100644
index 00000000..9eb50488
--- /dev/null
+++ b/npc/008-2-14/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-14: Hurnscald Clinic saves
+008-2-14,31,27,0 script #save_008-2-14_31_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-14/_warps.txt b/npc/008-2-14/_warps.txt
new file mode 100644
index 00000000..eba5adca
--- /dev/null
+++ b/npc/008-2-14/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-14: Hurnscald Clinic warps
+008-2-14,25,31,0 warp #008-2-14_25_31 1,0,008-2-13,24,29
diff --git a/npc/008-2-14/doctor.txt b/npc/008-2-14/doctor.txt
new file mode 100644
index 00000000..aac419e6
--- /dev/null
+++ b/npc/008-2-14/doctor.txt
@@ -0,0 +1,114 @@
+// Evol scripts.
+// Author:
+// gumi
+// The Mana World Project
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// The crazy Hurnscald Doctor.
+
+008-2-14,27,27,0 script Doctor NPC_DOCTOR_LEGACY,{
+ function doctorAxeHat;
+ function doctorEyePatch;
+
+ if (getequipid(EQI_HEAD_TOP) == AxeHat)
+ doctorAxeHat();
+ if (getequipid(EQI_ACC_R) == Eyepatch)
+ doctorEyePatch();
+
+ speech(4,
+ l("Hello, can I help you?"));
+
+ selectd(
+ l("I think I am sick!"),
+ l("No, I feel fine."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything strange in town? Anything that might have to do with the robberies?")));
+
+ switch (@menu)
+ {
+ case 1:
+ narrator(4,
+ l("The doctor examines you briefly."));
+ // TODO: check for poison or other status conditions currently in use
+ speech(
+ l("Nonsense!"),
+ l("You look fine and dandy to me."),
+ l("All you need is a bit more exercise and fresh fruit in your diet!"));
+ close;
+ case 2:
+ speech(
+ l("Then please stop wasting my precious time."));
+ close;
+ case 3:
+ speech(
+ l("No, I haven't seen anything."));
+ close;
+ }
+ end;
+
+function doctorAxeHat {
+ mesn;
+ mesq l("Oh my, what happened to you?");
+ next;
+ mesn;
+ mesq l("Wait. Thats just a fake. Shame on you!");
+ next;
+ mesn;
+ mesq l("Anyway...");
+ next;
+ return;
+}
+
+function doctorEyePatch {
+ mesn;
+ mesq l("Would you like a glass eye to replace that eye patch you have? We just got a whole load of them in today. I'll even let you keep the patch as a souvenir.");
+ next;
+ select
+ l("No, thank you."),
+ l("Yes, please.");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("If you change your mind, just say the word. Anyway...");
+ next;
+ return;
+ }
+ mesn;
+ mesq l("Now, where did I put that box of eyes...");
+ next;
+ mesn;
+ mesc l("He goes off to look for them and comes back empty handed.");
+ mesq l("I can't seem to find where I put that box. You should come back later, I may have found them by then.");
+ next;
+ mesn;
+ mesq l("Anyway...");
+ next;
+ return;
+}
+
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 3;
+ end;
+}
diff --git a/npc/008-2-14/mapflags.txt b/npc/008-2-14/mapflags.txt
new file mode 100644
index 00000000..4f5bd95c
--- /dev/null
+++ b/npc/008-2-14/mapflags.txt
@@ -0,0 +1 @@
+008-2-14 mapflag town
diff --git a/npc/008-2-15/_import.txt b/npc/008-2-15/_import.txt
new file mode 100644
index 00000000..c504df36
--- /dev/null
+++ b/npc/008-2-15/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-15: Hurnscald Farm
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-15/_warps.txt",
diff --git a/npc/008-2-15/_warps.txt b/npc/008-2-15/_warps.txt
new file mode 100644
index 00000000..3f3fb766
--- /dev/null
+++ b/npc/008-2-15/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-15: Hurnscald Farm warps
+008-2-15,35,34,0 warp #008-2-15_35_34 0,0,008-1,151,81
diff --git a/npc/008-2-16/_import.txt b/npc/008-2-16/_import.txt
new file mode 100644
index 00000000..5f5ea192
--- /dev/null
+++ b/npc/008-2-16/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-16: Hurnscald Cottage
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-16/_warps.txt",
+"npc/008-2-16/stove.txt",
+"npc/008-2-16/yannika.txt",
diff --git a/npc/008-2-16/_warps.txt b/npc/008-2-16/_warps.txt
new file mode 100644
index 00000000..bb2293f4
--- /dev/null
+++ b/npc/008-2-16/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-16: Hurnscald Cottage warps
+008-2-16,25,34,0 warp #008-2-16_25_34 0,0,008-1,275,75
diff --git a/npc/008-2-16/stove.txt b/npc/008-2-16/stove.txt
new file mode 100644
index 00000000..d4389f7a
--- /dev/null
+++ b/npc/008-2-16/stove.txt
@@ -0,0 +1,87 @@
+// Evol scripts.
+// Author:
+// Jesusalva
+// Description:
+// Stove to make sandwiches
+
+008-2-16,32,29,0 script Stove NPC_NO_SPRITE,{
+ // If player haven't finished Hinnak quest yet, they can't use the stove
+ .@q=getq(HurnscaldQuests_Hinnak);
+ if (.@q < 3)
+ {
+ setcamnpc "Yannika";
+ mesn l("Yannika");
+ mesq l("Please don't touch my stove without my authorization.");
+ close;
+ }
+
+ // Cooking loop
+ do
+ {
+ mesc l("It is time to make some sandwiches myself!");
+ mes "##B" + l("Drag and drop the items from your inventory in the frames.") + "##b";
+
+ // Crafting skin with 4 columns
+ setskin "craft4";
+ .@var$ = requestcraft(4); // Limit: 4 items
+ .@craft = initcraft(.@var$);
+ .@entry = findcraftentry(.@craft, CRAFT_COOKING);
+ setskin "";
+
+ // Does the recipe exist and is a sandwich?
+ if (.@entry < 0)
+ {
+ narrator
+ l("You don't know how any recipe with that."),
+ l("Do you want to try again?");
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ else
+ {
+ // Did player cheat? If not, proceed with the craft
+ if (!validatecraft(.@craft))
+ {
+ narrator
+ l("Where are the ingredients?");
+ .@tryAgain=true;
+ }
+ else
+ {
+ // Even if the recipe is right, if you don't have it on your
+ // recipe book, it should be deemed invalid.
+ if (RECIPES[.@entry])
+ {
+ usecraft .@craft;
+ narrator
+ l("Done!"),
+ l("Do you want to try again?");
+ }
+ else
+ {
+ narrator
+ l("You don't know how any recipe with that."),
+ l("Do you want to try again?");
+ }
+
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ }
+
+ // Clear unused variables and clear the screen.
+ deletecraft .@craft;
+ clear;
+ } while (.@tryAgain);
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/008-2-16/yannika.txt b/npc/008-2-16/yannika.txt
new file mode 100644
index 00000000..05c8a41e
--- /dev/null
+++ b/npc/008-2-16/yannika.txt
@@ -0,0 +1,469 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// Yannika, Hinnaks Wife.
+// Makes delicious sandwiches for the player
+// Variables:
+// General_Cooking
+// 0: Doesn't knows the quest
+// 1: Received the quest for the Cookbook
+// 2: Completed the quest for the Cookbook
+// RECIPES
+// Controls which recipes you know and doesn't.
+// It is an array with Craft Constants.
+
+008-2-16,28,29,0 script Yannika NPC_YANNIKA,{
+ function yannika_intro;
+ function yannika_knives;
+ function yannika_recipe;
+ function sudo_make_sandwich;
+ function teach_cooking;
+
+ // If player haven't finished Hinnak quest yet, Yannika says so
+ .@q=getq(HurnscaldQuests_Hinnak);
+ if (.@q < 3)
+ {
+ speech
+ l("Hello."),
+ l("Isn't my husband Hinnak so hardworking?"),
+ l("Come back later.");
+ close;
+ }
+
+ // Player completed Hinnak quest, we can continue in making Sandwiches
+ switch (getq(.quest))
+ {
+ case 0:
+ yannika_intro();
+ break;
+ case 1:
+ yannika_knives();
+ break;
+ default:
+ speech
+ l("Hello."),
+ l("Thanks for helping my husband Hinnak."),
+ l("He likes to eat sandwiches. A good thing they are so easy to make!");
+
+ select
+ l("Easy to make? Could you make one for me?"),
+ l("Easy to make? Could you teach me how to make them?"),
+ l("Good to know, thanks.");
+ mes "";
+
+ if (@menu == 1)
+ sudo_make_sandwich();
+ else if (@menu == 2)
+ teach_cooking();
+
+ next;
+ break;
+ }
+ closeclientdialog;
+ goodbye;
+ close;
+
+
+
+ ////////////////////////////////////////////////////
+ // Quest state 0
+ function yannika_intro
+ {
+ speech
+ l("Hello."),
+ l("Thanks for helping my husband Hinnak."),
+ l("Could you please bring me 2 new knives?"),
+ l("Hinnak wasted all my good kitchen knives trying to get rid of his accursed Pinkies.");
+
+ select
+ l("Yes, sure thing."),
+ l("Not my problem.");
+
+ if (@menu == 1)
+ {
+ speech
+ l("I'll be waiting for you, then!");
+ setq .quest, 1;
+ next;
+ }
+ }
+
+ // Quest state 1
+ function yannika_knives
+ {
+ speech
+ l("Hello."),
+ l("Thanks for helping my husband Hinnak."),
+ l("Did you brought me 2 new knives?");
+
+ select
+ rif(countitem(Knife) >= 2, l("Yes, here they are.")),
+ l("Not yet, I'll be back.");
+
+ if (@menu == 1)
+ {
+ // No need to countitem() because it is already at the menu
+ // Technically, a hacked client could bypass earlier check though
+ // Jesusalva doesn't likes hacks, so he puts delitem first.
+ // delitem halts the script if it cannot delete all items.
+ inventoryplace RecipeBook, 1;
+ delitem Knife, 2;
+ getitembound RecipeBook, 1, IBT_ACCOUNT;
+ setq .quest, 2;
+
+ speech
+ l("Many thanks. I can now do sandwiches again!"),
+ l("Well, of course. First of all, you need a @@. You can have mine, if you want.", getitemlink(RecipeBook)),
+ l("The recipes, of course, you must collect yourself. Even sandwiches are not so simple as to simply put ingredients and hope for the best."),
+ l("Cooking is an art. You need to know how to cook something. You can use my stove to prepare."),
+ l("Or, you can just forget all that, and let me prepare sandwiches for you, too! %%H"), // %%H - Smile Emote
+ l("Oh, but I'll still need the book. Even if all pages are white.");
+ next;
+ }
+ }
+
+ // Learn a new Sandwich Recipe
+ // yannika_recipe ( Craft ID, Sandwich ID, Ammo 1, Item 1, Ammo 2, Item 2, Ammo 3, Item 3, {alt1, alt2} )
+ function yannika_recipe
+ {
+ .@craft=getarg(0);
+ .@sanid=getarg(1);
+ .@ammo1=getarg(2);
+ .@item1=getarg(3);
+ .@ammo2=getarg(4);
+ .@item2=getarg(5);
+ .@ammo3=getarg(6);
+ .@item3=getarg(7);
+ .@alt1=getarg(8);
+ .@alt2=getarg(9);
+ mesn;
+ mes l("For this recipe, you'll need to bring me:");
+ mesf("%d/%d %s", countitem(.@item1), .@ammo1, getitemlink(.@item1));
+ mesf("%d/%d %s", countitem(.@item2), .@ammo2, getitemlink(.@item2));
+ mesf("%d/%d %s", countitem(.@item3), .@ammo3, getitemlink(.@item3));
+ mesf("%s or %s", getitemlink(.@alt1), getitemlink(.@alt2));
+
+ select
+ rif(countitem(.@alt1), l("(%s) Yes, in fact, you can take them now.", getitemname(.@alt1))),
+ rif(countitem(.@alt2), l("(%s) Yes, in fact, you can take them now.", getitemname(.@alt2))),
+ l("Maybe later.");
+
+ if (@menu < 3)
+ {
+ if (countitem(.@item1) < .@ammo1 ||
+ countitem(.@item2) < .@ammo2 ||
+ countitem(.@item3) < .@ammo3)
+ {
+ speech
+ l("You don't have everything I have asked for.");
+ close;
+ }
+ delitem .@item1, .@ammo1;
+ delitem .@item2, .@ammo2;
+ delitem .@item3, .@ammo3;
+ if (@menu == 1)
+ delitem .@alt1, 1;
+ if (@menu == 2)
+ delitem .@alt2, 1;
+
+ // Learn recipe
+ RECIPES[.@craft]=true;
+ mesn;
+ mesq l("Look and learn.");
+ next;
+ mesn;
+ mesq l("This is how you do it! HAAH!");
+ next;
+ mesc l("You learned how to cook @@.", getitemlink(.@sanid));
+ next;
+ mesn;
+ mesq l("Please come back later and I may have something else to show you.");
+ }
+ return;
+ }
+
+ // Yannika can make sandwiches for players
+ // FIXME: Actually, Yannika will cook anything for players >__>
+ function sudo_make_sandwich
+ {
+ speech
+ l("When cooking, the order of ingredients matter."),
+ l("Even a simple sandwich will be ruined if you place lettuce above the cheese!"),
+ l("Anyway, to make a sandwich, you'll need to place, in this order:"),
+ l("1x @@, 3x @@, 2x @@, and the ingredient of your choice.", getitemlink(Bread), getitemlink(LettuceLeaf), getitemlink(Cheese));
+
+ do
+ {
+ mes "##B" + l("Drag and drop the items from your inventory in the frames.") + "##b";
+
+ // Crafting skin with 4 columns
+ setskin "craft4";
+ .@var$ = requestcraft(4); // Limit: 4 items
+ .@craft = initcraft(.@var$);
+ .@entry = findcraftentry(.@craft, CRAFT_COOKING);
+ setskin "";
+
+ // Does the recipe exist and is a sandwich?
+ if (.@entry < 0)
+ {
+ speech
+ l("Sorry. I can't make a sandwich with that."),
+ l("Do you want to try again?");
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ else
+ {
+ // Did player cheat? If not, proceed with the craft
+ if (!validatecraft(.@craft))
+ {
+ speech
+ l("Sorry, my eyesight is a bit poor nowadays. Where are the ingredients?");
+ .@tryAgain=true;
+ }
+ else
+ {
+ usecraft .@craft;
+ speech
+ l("@@ skillfully cuts the bread in half, throws the ingredients in air, and they land in the sandwich!", .name$),
+ l("There you go. Please enjoy yourself! ^.^");
+
+ .@tryAgain=false;
+ }
+ }
+
+ // Clear unused variables and clear the screen. Then print recipe again.
+ deletecraft .@craft;
+ if (.@tryAgain) {
+ clear;
+ mesc l("1x @@, 3x @@, 2x @@, and the ingredient of your choice.", getitemlink(Bread), getitemlink(LettuceLeaf), getitemlink(Cheese));
+ }
+ } while (.@tryAgain);
+ return;
+ }
+
+ // Teach player how to cook, providing a recipe book if they don't have one
+ function teach_cooking
+ {
+ // Check if your stats aren't enough (bonuses aren't counted)
+ if (readparam(bInt) < 10 ||
+ readparam(bDex) < 20)
+ {
+ speech
+ l("Well, cooking is an art, and thus, you need intelligence and dexterity to learn."),
+ l("Please come again with at least 10 INT and 20 DEX. Stat Bonuses aren't counted.");
+ close;
+ }
+
+ // First part: Carp Sandwich
+ if (!RECIPES[CraftCarpSandwich]) {
+ mesn;
+ mesq l("Well, of course, I can show you how to cook sandwiches. But you'll need to bring ingredients for practice.");
+ next;
+ mesn;
+ mesq l("Should we start with something simple? Hmmm... Do you have a %s? It is hard to find one around these parts, but you don't seem to be from here.", getitemlink(FishingRod));
+ next;
+ // pre-req
+ if (!countitem(FishingRod)) {
+ mesn;
+ mesq l("Please try getting one. You'll need some carps for the recipe I'm going to teach you.");
+ if (countitem(CommonCarp) || countitem(GrassCarp))
+ mesq l("Cooking begins with collecting your own ingredients. That is what makes it so tasty. So, bring me a fishing rod!");
+ return;
+ }
+ // warn about main req
+ if (!countitem(CommonCarp) && !countitem(GrassCarp)) {
+ mesn;
+ mesq l("Ah, good, you've brought one!");
+ next;
+ mesn;
+ mesq l("Now you'll need to fish a carp. It can be a %s or a single %s, for the sandwhich.", getitemlink(CommonCarp), getitemlink(GrassCarp));
+ next;
+ }
+ mesn;
+ mesq l("I'll also be needing the usual sandwich stuff: Bread, Lettuce and Cheese.");
+ next;
+ yannika_recipe(CraftCarpSandwich, CarpSandwich, 1, Bread, 3, LettuceLeaf, 2, Cheese, CommonCarp, GrassCarp);
+ return;
+ }
+
+ // Main quest (TODO)
+ .@q=getq(.quest);
+ .@q2=getq2(.quest);
+ .@s=getq(General_SmearedHands);
+
+ // Snarfles/Crane dependency
+ if (!.@s) {
+ mesn;
+ mesq l("No, not at the moment.");
+ next;
+ return;
+ }
+
+ // Backup SmearedHands to cooking for ease of access
+ setq2 General_Cooking, getq2(General_SmearedHands);
+
+ // Switch General_Cooking quest
+ switch (.@q) {
+ case 2:
+ setq1 General_Cooking, 3;
+ // FALLTHROUGH
+ case 3:
+ case 4:
+ case 5:
+ case 9:
+ case 10:
+ case 12:
+ case 13:
+ case 14:
+ case 17:
+ mesn;
+ mesq l("Could you do a favor for me, first?");
+ next;
+ mesn;
+ mesq l("Could you bring a couple fresh fish to %s? Carps should do.", b(l("the Chef in Dimond's Cove")));
+ next;
+ mesn;
+ mesq l("He promised to make me some %s if I could provide him the fish.", getitemlink(SeafoodPlate));
+ next;
+ mesn;
+ mesq l("Sandwiches are handy, but they won't beat a full meal, which we hadn't in a while.");
+ next;
+ mesn;
+ mesq l("I'll be waiting your return!");
+ next;
+ break;
+ case 6:
+ select
+ l("What did you want, again?"),
+ l("I need some %s.", getitemname(.@q2 == VEGAN ? MananaSandwich : PioulegSandwich));
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("A %s pretty please.", getitemlink(SeafoodPlate));
+ break;
+ }
+ mesn;
+ mesq l("Ehh, I usually only make %s... You know cooking is not just throwing ingredients and vói-la, right?", getitemlink(CarpSandwich));
+ next;
+ mesn;
+ mesq l("But actually... Perhaps the chef in Candor?");
+ next;
+ mesn;
+ mesq l("I forgot their name, but they are not very normal. Err.");
+ next;
+ mesn;
+ mesq l("You probably can find them by the shorelines.");
+ setq1 General_Cooking, 7;
+ break;
+ case 7:
+ mesn;
+ mesq l("Candor's Chef is not very normal, so be careful when asking him about the sandwiches you want to make.");
+ break;
+ case 8:
+ mesn;
+ mesq l("How things went with Candor's Chef?");
+ next;
+ select
+ l("Great!"),
+ l("Not so great!");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("That's good to hear!");
+ } else {
+ mesn;
+ mesq l("Oh no... Did he asked you to help you with something crazy? I feared he would do that...");
+ next;
+ mesn;
+ mesq l("But that's how I learned the carp sandwich recipe, you know?");
+ next;
+ mesn;
+ mesq l("Was trying to eat fried carp, but it always smeared my hands. Never thought he would come up with a sandwich recipe when I gave him that!");
+ next;
+ mesn;
+ mesq l("But he is still crazy, in my opinion...");
+ }
+ break;
+ case 11:
+ select
+ l("What did you want, again?"),
+ l("Do you know where Tulimshar bakery is?");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("A %s pretty please.", getitemlink(SeafoodPlate));
+ break;
+ }
+ mesn;
+ mesq l("What, don't tell me you never have been at Tulimshar! Nearly everyone of your age already has been there at least once.");
+ next;
+ mesn;
+ mesq l("Tulimshar used to have a great Inn, but after the war, their business started to decline.");
+ next;
+ mesn;
+ mesq l("However, they had a bakery which has since flourished!");
+ next;
+ mesn;
+ mesq l("So if you fail finding the bakery, look for the Inn - it is on the same building.");
+ break;
+ case 15:
+ case 16:
+ select
+ l("What did you want, again?"),
+ l("Where can I find salad?");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("A %s pretty please.", getitemlink(SeafoodPlate));
+ break;
+ }
+ mesn;
+ mesq l("This is a strange question. But I might be able to answer.");
+ next;
+ mesn;
+ mesq l("Hubby exports a lot of crops to Tulimshar. The purchaser is the Magic Academy of Tulimshar.");
+ next;
+ mesn;
+ mesq l("I'm not sure if this is of any help to you, though? I forgot who is the responsible for the Academy, so good luck!");
+ break;
+ case 18:
+ mesn;
+ mesq l("So? Did you got me a %s? I'm hungry...", getitemlink(SeafoodPlate));
+ next;
+ if (countitem(SeafoodPlate) < 1)
+ break;
+ if (askyesno() == ASK_NO)
+ break;
+ delitem SeafoodPlate, 1;
+ getitem EmptyPlate, 1;
+ quest_xp(.maxLevel, 10000);
+ quest_jxp(.maxLevel, 1000);
+ setq1 General_Cooking, 19;
+ mesn;
+ mesq l("Ah - Many thanks. Here, I'll return you a plate.");
+ next;
+ mesc l("Food Questline Complete!");
+ mesc l("Stay tuned for more updates!");
+ mes "";
+ mesc l("- The Mana World Development Team");
+ break;
+ default:
+ mesn;
+ mesq l("No, not at the moment.");
+ }
+
+ return;
+ }
+
+OnInit:
+ .maxLevel = 40;
+ .distance = 4;
+ .quest=General_Cooking;
+
+ end;
+}
diff --git a/npc/008-2-17/_import.txt b/npc/008-2-17/_import.txt
new file mode 100644
index 00000000..854dad03
--- /dev/null
+++ b/npc/008-2-17/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-17: Mining Camp
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-17/_warps.txt",
+"npc/008-2-17/angus.txt",
+"npc/008-2-17/caul.txt",
diff --git a/npc/008-2-17/_warps.txt b/npc/008-2-17/_warps.txt
new file mode 100644
index 00000000..1010521a
--- /dev/null
+++ b/npc/008-2-17/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-17: Mining Camp warps
+008-2-17,52,40,0 warp #008-2-17_52_40 0,0,008-1,236,40
+008-2-17,25,39,0 warp #008-2-17_25_39 1,0,008-2-18,22,24
+008-2-17,24,34,0 warp #008-2-17_24_34 0,0,008-2-19,20,29
diff --git a/npc/008-2-17/angus.txt b/npc/008-2-17/angus.txt
new file mode 100644
index 00000000..b51f1dcd
--- /dev/null
+++ b/npc/008-2-17/angus.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Angus the Smith.
+// THIS IS A PLACEHOLDER!
+
+008-2-17,34,47,0 script Angus NPC_ANGUS_THE_SMITH,{
+ speech
+ l("Hello."),
+ l("Do you need your pickaxe or your shovel fixed? Then I am your man."),
+ l("If you want to play with unicorns, you better piss off now.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-17/caul.txt b/npc/008-2-17/caul.txt
new file mode 100644
index 00000000..00515a89
--- /dev/null
+++ b/npc/008-2-17/caul.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Caul the Alchemist.
+// THIS IS A PLACEHOLDER!
+
+008-2-17,40,33,0 script Caul NPC_CAUL,{
+ speech
+ l("Hi there."),
+ l("Don't you like the smoke, when there is a nice fire beneath a cauldron?"),
+ l("Honestly, sometimes I prefer nice explosions. Better keep back!");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-18/_import.txt b/npc/008-2-18/_import.txt
new file mode 100644
index 00000000..5035c75c
--- /dev/null
+++ b/npc/008-2-18/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-18: Mining Camp First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-18/_warps.txt",
+"npc/008-2-18/malik.txt",
diff --git a/npc/008-2-18/_warps.txt b/npc/008-2-18/_warps.txt
new file mode 100644
index 00000000..a80310cd
--- /dev/null
+++ b/npc/008-2-18/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-18: Mining Camp First Floor warps
+008-2-18,22,26,0 warp #008-2-18_22_26 1,0,008-2-17,25,40
diff --git a/npc/008-2-18/malik.txt b/npc/008-2-18/malik.txt
new file mode 100644
index 00000000..eb091e35
--- /dev/null
+++ b/npc/008-2-18/malik.txt
@@ -0,0 +1,64 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+// TODO: Make Malik prepare Crude Gem from shards, and make him produce Gem Powder later, once the player visited Tulim(dont tell WildX, though)
+
+008-2-18,32,24,0 script Malik#008-2-18 NPC_MALIK,{
+ if (getq(.quest_inspector) == 11)
+ {
+ speech(4,
+ l("Hi, can I help you at all?"));
+
+ selectd(
+ l("The inspector sent me here to investigate."));
+
+ speech(4,
+ l("Yeah, we did hear a commotion."),
+ l("We thought we heard someone go down to the basement, but we checked the whole place over and didn't see anything out of the ordinary."));
+
+ close2;
+ setq(.quest_inspector, 12);
+ end;
+ }
+
+ npctalk3(generic(32 | 256));
+ end;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-2-19/_import.txt b/npc/008-2-19/_import.txt
new file mode 100644
index 00000000..1d12e589
--- /dev/null
+++ b/npc/008-2-19/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-19: Mining Camp Basement
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-19/_warps.txt",
+"npc/008-2-19/books.txt",
diff --git a/npc/008-2-19/_warps.txt b/npc/008-2-19/_warps.txt
new file mode 100644
index 00000000..ec68b70c
--- /dev/null
+++ b/npc/008-2-19/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-19: Mining Camp Basement warps
+008-2-19,20,26,0 warp #008-2-19_20_26 0,0,008-2-17,24,32
diff --git a/npc/008-2-19/books.txt b/npc/008-2-19/books.txt
new file mode 100644
index 00000000..2c6a2112
--- /dev/null
+++ b/npc/008-2-19/books.txt
@@ -0,0 +1,60 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-2-19,33,21,0 script bookcase NPC_NO_SPRITE,{
+
+ if (getq(.quest_inspector) != 12)
+ {
+ dispbottom(l("You see an ordinary bookcase."));
+ end;
+ }
+
+ narrator(
+ l("You see an ordinary bookcase."),
+ l("Looking over closely, you find a book that is upside down."),
+ l("The book has been hollowed out."),
+ l("Inside is a theater mask and a note that you cannot even begin to read."));
+
+ close2;
+ setq(.quest_inspector, 13);
+ end;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 1;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-2-2/_import.txt b/npc/008-2-2/_import.txt
new file mode 100644
index 00000000..92597add
--- /dev/null
+++ b/npc/008-2-2/_import.txt
@@ -0,0 +1,12 @@
+// Map 008-2-2: The Rusty Pick
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-2/_warps.txt",
+"npc/008-2-2/barron.txt",
+"npc/008-2-2/jukebox.txt",
+"npc/008-2-2/kfahr.txt",
+"npc/008-2-2/ledmitz.txt",
+"npc/008-2-2/mapflags.txt",
+"npc/008-2-2/melania.txt",
+"npc/008-2-2/melinda.txt",
+"npc/008-2-2/note.txt",
+"npc/008-2-2/shop.txt",
diff --git a/npc/008-2-2/_warps.txt b/npc/008-2-2/_warps.txt
new file mode 100644
index 00000000..d7cce7fc
--- /dev/null
+++ b/npc/008-2-2/_warps.txt
@@ -0,0 +1,6 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-2: The Rusty Pick warps
+008-2-2,28,34,0 warp #008-2-2_28_34 0,0,008-1,236,103
+008-2-2,52,26,0 warp #008-2-2_52_26 1,0,008-2-3,66,28
+008-2-2,24,29,0 warp #008-2-2_24_29 0,0,008-2-4,43,28
+008-2-2,52,32,0 warp #008-2-2_52_32 0,0,008-2-5,24,25
diff --git a/npc/008-2-2/barron.txt b/npc/008-2-2/barron.txt
new file mode 100644
index 00000000..e46ebe6a
--- /dev/null
+++ b/npc/008-2-2/barron.txt
@@ -0,0 +1,32 @@
+// Evol scripts.
+// Author:
+// Micksha
+// toams
+// Description:
+// Barron, the bartender of the Rusty Pick.
+
+008-2-2,43,28,0 script Barron#008-2-2 NPC_GENERAL_STORE,{
+speech S_LAST_NEXT,
+ l("Hi!"),
+ l("I am the bartender here, can I provide you with some delicious beverage?"),
+ l("Or you can take seat and ask Melinda if you need something.");
+
+ switch (select(l("What beverages do you have?"),
+ l("I'll ask Melinda later")))
+ {
+ case 1:
+ closeclientdialog;
+ shop "#Invisible008-2-2";
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("Make sure to tip her, it will brighten up her day.");
+ close;
+ }
+
+
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/008-2-2/jukebox.txt b/npc/008-2-2/jukebox.txt
new file mode 100644
index 00000000..6e592c8f
--- /dev/null
+++ b/npc/008-2-2/jukebox.txt
@@ -0,0 +1,29 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Hocus Pocus Fidibus
+// Description:
+// Music box for a classy AFKing experience
+// GMs can play on whole map but default to player only
+
+008-2-2,39,27,0 script #JukeboxHurns NPC_JUKEBOX,{
+ mesc l("Select a music");
+ .@track="jukebox"::HurnscaldPrompt();
+ .@global=ASK_NO;
+ if (is_evtc()) {
+ mes "Play music globally?";
+ mes "* Selecting \"No\" will play only to yourself (default behavior)";
+ .@global=askyesno();
+ }
+ if (.@global == ASK_YES)
+ "jukebox"::BroadcastMusic(getmap(), .@track);
+ else
+ "jukebox"::JukeboxMusic(.@track);
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
+
diff --git a/npc/008-2-2/kfahr.txt b/npc/008-2-2/kfahr.txt
new file mode 100644
index 00000000..4482b4fd
--- /dev/null
+++ b/npc/008-2-2/kfahr.txt
@@ -0,0 +1,785 @@
+// Evol scripts.
+// Author:
+// Addapted for TMW rEvolt by Toams
+// Author(s) of original script: Jaxad0127 (02/11/2008)
+// Additional contributors: o11c, wushin, Jessica Beller (jtoelke), Ablu, Turmfalke
+// Description:
+// Kfahr the hero. Bone knife quest and Golden Stinger quest (Needed for Setzer Quest)
+// Variables:
+// HurnscaldQuests_Kfahr
+// Values:
+// 0 Didn't speak with Kfahr yet.
+// 1 Already met Kfahr, No quests started
+// 2 Bone knife quest started.
+// 3 Bone knife quest finished
+
+
+008-2-2,44,36,0 script Kfahr NPC_YOUNG_MAN_KFAHR,{
+ @beer_count = 0;
+ @current_story = 0;
+ @last_story = 0;
+ @has_beer = 0;
+
+ function kfahr_first_met;
+ function kfahr_default_greeting;
+ function kfahr_main_dialog;
+ function tale_check;
+ function gain_power;
+ function give_beer;
+ function pc_no_beer;
+ function kfahr_has_beer;
+ function kfahr_drunk;
+ function tale_desert_worm;
+ function desert_worm_see_bones;
+ function tale_desert_worm_final;
+ function tale_desert_temple;
+ function tale_hero_tulimshar;
+ function tale_desert;
+ function bone_quest;
+ function bone_quest_tooweak;
+ function bone_quest_items;
+ function bone_quest_check_items;
+ function bone_quest_final_check;
+ function bone_quest_finished;
+
+switch (getq(HurnscaldQuests_Kfahr)) {
+ case 0:
+ narrator S_LAST_NEXT,
+ l("You stand before a battle-scarred, darkly tanned warrior, brimming with muscles."),
+ l("Just looking at him you smell danger, adventure, excitement..."),
+ l("..."),
+ l("On second thought, he really could use a bath."),
+ l("..."),
+ l("The warrior turns towards you, grinning broadly.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Why, hello there! Come to visit Kfahr the Warrior to hear of my exploits, have you?");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He laughs heartily and gives you a slap on the back.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Can't blame you, can't blame you at all! Here, take a seat!");
+ select
+ l("Who are you?"),
+ l("Goodbye.");
+ switch (@menu) {
+ case 1:
+ kfahr_first_met;
+ break;
+ case 2:
+ close;
+ }
+ break;
+ case 1:
+ kfahr_default_greeting;
+ kfahr_main_dialog;
+ break;
+ case 2:
+ bone_quest_check_items;
+ kfahr_main_dialog;
+ break;
+ default:
+ kfahr_default_greeting;
+ kfahr_main_dialog;
+ break;
+}
+
+close;
+
+function kfahr_first_met {
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr laughs again.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Surely you jest! You must have heard of Kfahr, Slayer of Toby Rick the Desert Worm, Raider of the Lost Temple, Hero of Tulimshar?");
+
+ select
+ l("Uhm..."),
+ l("Well..."),
+ l("To be quite honest..."),
+ l("Excuse me, someone is, er, whispering me...");
+ switch (@menu) {
+ case 4:
+ close;
+ default:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("ah, I knew it! So you have come to hear some tales about the dangers of the desert? You've come to the right man!");
+ setq HurnscaldQuests_Kfahr, 1;
+ kfahr_main_dialog;
+ }
+
+ return;
+}
+
+function kfahr_default_greeting {
+ narrator S_LAST_NEXT,
+ l("Kfahr nods and grins as you greet him.");
+ speech S_LAST_NEXT,
+ l("Came back for more stories about Desert Worms, Desert Temples and the Hero of Tulimshar? Have a seat!");
+
+ return;
+}
+
+function kfahr_main_dialog {
+ do {
+ select
+ l("What's a Desert Worm?"),
+ l("Desert Temple?"),
+ l("Hero of Tulimshar?"),
+ l("Tell me about the desert!"),
+ l("I want to become as powerful as you!"),
+ l("Here, have a beer!"),
+ l("Goodbye!");
+ switch (@menu) {
+ case 1:
+ tale_desert_worm;
+ break;
+ case 2:
+ tale_desert_temple;
+ break;
+ case 3:
+ tale_hero_tulimshar;
+ break;
+ case 4:
+ tale_desert;
+ break;
+ case 5:
+ gain_power;
+ break;
+ case 6:
+ give_beer;
+ break;
+ case 7:
+ close;
+ }
+ } while (1);
+
+ return;
+}
+
+function tale_check {
+ //don't to tell the same story again
+ if (@current_story == @last_story) {
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr frowns.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I only just told you that story. Trust me, the others are worth hearing, too!");
+ return true;
+ }
+
+ //don't to tell a story if out of beer
+ if (@has_beer == 0) {
+ if (@beer_count > 4) {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I think I've talked 'nuff for now... but thanks for lis'ning!");
+ }
+ if (@beer_count <= 4) {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Now that's one of my favorite tales, but my throat is just a little too dry to talk about something like that... could you help me out a little here?");
+ }
+ return true;
+ }
+ @has_beer = 0;
+ @last_story = @current_story;
+
+ return false;
+}
+
+function gain_power {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Yeees, yes... doesn't everyone?");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He laughs briefly.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Don't worry – you can't become as powerful as I, of course, but if you keep practicing, you can get pretty damn close! Just make sure to pick your opponents carefully, and know when to run to live another day!");
+
+ return;
+}
+
+function give_beer {
+
+ if (countitem(Beer) < 1) {
+ pc_no_beer();
+ return;
+ }
+
+ if (@has_beer) {
+ kfahr_has_beer();
+ return;
+ }
+ else {
+ @has_beer = 1;
+ delitem Beer, 1;
+ }
+
+ if (@beer_count > 4) {
+ kfahr_drunk();
+ return;
+ }
+
+ ++@beer_count;
+
+ setarray .beermessages$[1],
+ l("Ah yes... a warrior's drink!"),
+ l("Generous, generous! I like that!"),
+ l("Hahah! That's just what I needed!"),
+ l("I love this town! Hurnscaldian hospitality! Mrahahahah!"),
+ l("A'ight, one more can't hurt, eh?");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr is visibly delighted.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ .beermessages$[@beer_count];
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He takes a deep sip.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Aaah, magnificent!");
+ if (@beer_count > 4)
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr seems quite relaxed now.");
+
+ return;
+}
+
+function pc_no_beer {
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr stares at you, then begins to laugh.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Mrahahahahaha! Here's the beer! Right, right! Naah, I get it! Save your gold for whatever you need it for! But if you have some spare and want to share a beer, you know where to find me!");
+
+ return;
+}
+
+function kfahr_has_beer {
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr leans back and sighs heavily.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Generous, generous! But I still have plenty in here!");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He laughs and takes a sip from the beer you gave him earlier.");
+
+ return;
+}
+
+function kfahr_drunk {
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr leans back and sighs heavily.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Very, very generous... bu' I think I'm fine for now.");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He suppresses a burp.");
+
+ return;
+}
+
+function tale_desert_worm {
+ @current_story = 1;
+ if (tale_check())
+ return;
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr smiles and leans back.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("A desert worm is probably the largest creature you will ever see, larger even than most dragons. It spans a good twenty chains (or six box tosses if you're used to the Imperial system) in length, has a thick, rubbery skin, and teeth as long as my legs."),
+ l("Most are a darkish gray, except for the young ones; those are more purplish, I've been told. Well, anyway, you hardly ever see one of them in their entirety, you only see the head, if they decide to come out and fight – they tend to burrow under the ground.");
+ l("They are terrifying beasts, but lack any intelligent thought whatsoever. They just eat whatever gets in their way. There's nothing out there that can kill one, I think, and they can grow hundreds of years old."),
+ l("Fortunately, they're kind of rare these days, and mostly roam in the empty deserts far, far south of Tulimshar. They don't like the area too close to the mountains, I think; probably too rocky underground.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr takes a sip from his beer.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Anyway. Desert worms are dangerous, as I said, but there was one particularly terrifying one, called Toby Rick. You must've heard of it – the greatest and most dangerous worm, scourge of the trade routes. It could smell humans from miles away."),
+ l("Most desert worms don't smell or see or feel much, you see. They just notice when something's walking nearby, then jump up and swallow it. But Toby Rick was different. He was a terrifying beast, three times as long as a regular worm."),
+ l("So to feed itself, it had learned to smell. That's right, the beast had grown nostrils and learned how to use 'em!"),
+ l("One day I was hired to protect a caravan going north to Tulimshar, with a friend of mine, old Arvek. He only came along for the fun, of course; it's not as if I really need much help defending a caravan... or at least normally it isn't."),
+ l("Arvek's fun to have about. His manners are as bad as his breath, but he knows how to make a laugh out of everything. One thing you musnt't ever do with him, though, and that is to try his `homebrew' -- some kind of ale he makes out of maggot slime...");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr takes another sip of beer, momentarily irritated as if surprised by the taste.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Anyway, This time was different. We were barely three days out in the desert, when we spotted him – `the Black Worm!', the Caravan Master cried, `Over there; it will kill us all!'"),
+ l("I had barely enough time to draw out my sword, and the beast was upon us! The caravan people were fleeing for their lives, so it was up to me and Arvek to stop it."),
+ l("That was madness, of course; no-one takes on a desert worm, if they have a choice. But we didn't; you see, with most desert worms you can just stand still and it won't notice you and pass by. But not with this one!");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr leans forward.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("So this humongous beast came roaring towards us, a big back hole where the mouth is, spikey fins sticking out to the side, all ready to swallow us all! My sword felt like a toothpick against that monster!");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He pauses, then leans back a little to take another long sip from his beer.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("So it seemed that our last hour was at hand, that we'd be swallowed and never heard from again!"),
+ l("Aha, but Kfahr doesn't die quite so easily. What happened was this: Me and Arvek charged towards that thing, slashing and stabbing, but our blows would just glance off. The beast roared and just slid by us, slapping us to the side with its fins like maggots, knocking us to the ground."),
+ l("It bolted up into the air, and tore down on the caravan, swallowing each and everyone in there in a single big gulp!"),
+ l("Then it turned around towards us. Those fins had hit us pretty badly; I had lost my shield and Arvek his backpack. Better for him, I suppose, but I had been rather fond of that shield – not that it would have helped me much here...");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr leans forward, nearly knocking over his beer.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("So the beast charges at the two of us again and we dodge – Arvek left, me right. The beast is smarter than the average desert worm, though, and had expected that – so it bends to the side and swallows poor Arvek, hair and hide and all.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr's eyes sparkle with excitement.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It turns around, trying to get me too. I dodge it – left, then the same again, I dodge it right. But it can't go on like that, the beast isn't tiring, but I am..."),
+ l("So for one instant I think that this might be it, that I might die out there! A worthy death, I suppose, against the king of desert worms! And just as I think that, I bump against something.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr slaps on the table.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Arvek's backpack! Doesn't sound terribly exciting, of course – what am I going to do, toss it at the beast and hope that it chokes on it?");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He grins.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("But I remember something better. That beast had grown nostrils, right? So it can smell and taste! So I tear open his backpack and pull out that big snakeskin of that disgusting maggot ale of his. It's still filled to the brim."),
+ l("I quickly put on my gloves again, because I don't want to touch that stuff with my bare skin. The beast is almost upon me, but I have only that one chance – so I squeeze the skin while sticking my thumb into the opening, until I can see the black of its nostrils..."),
+ l("...and when I think it's almost too late already, I shoot out that revolting brew at the beast's smelling holes, and I hit! Two at once, and up and sideways it rolls, away from me, and roaring and bellowing in pain!"),
+ l("It roared for a good five minutes, then convulsed... and first it spat out old Arvek, who was a bit irritated at all that because, as he told me, he had 'almost pierced the pancreas', whatever that means..."),
+ l("Next it spat out the caravan, and then some other caravan it had plucked off from elswehere. Somehow, everyone from there was still alive, too."),
+ l("Then it slid away from us, away to the north, but we could see it getting slower and slower."),
+ l("Two days later we caught up with it, but it was already dead then and had started to smell. We looked around and inside of it, found treasures and remnants of some less fortunate caravans and split them up appropriately."),
+ l("I never told Arvek that it was his brew that killed it; he'd never have forgiven me."),
+ l("One of the nomads that had been travelling with the other caravan then told me that you could make special kinds of knives and swords and armor out of desert worm bones.");
+
+ select
+ l("Hang on... bones in a... worm?"),
+ l("That's neat! Do you have any that I could see?"),
+ l("And then?"),
+ l("Zzzzzzzz.......");
+ switch (@menu) {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Weren't you listening? A desert worm is not a regular worm; a worm couldn't survive in the desert.");
+ select
+ l("Do you have any bones that I could see?"),
+ l("Never mind that, what happened then?"),
+ l("Zzzzzzzz.......");
+ switch (@menu) {
+ case 1: desert_worm_see_bones;
+ return;
+ case 2: tale_desert_worm_final;
+ return;
+ case 3: close;
+ }
+ case 2: desert_worm_see_bones;
+ return;
+ case 3: tale_desert_worm_final;
+ return;
+ case 4: close;
+ }
+
+ return;
+}
+
+function desert_worm_see_bones {
+ if (BaseLevel >= 40) {
+ bone_quest;
+ return;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Of course!");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He pulls out a strangely curved knife with a yellow-whiteish blade that is almost transparent at the edge.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("When hardened properly, this bone knife can last a lifetime! One of the best knives you will find, too.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He puts the knife back into his pocket.");
+
+ mes l(" > \"That knife looks sharp!\"");
+ mes "";
+ mes l(" > \"But, what happened next?\"");
+ tale_desert_worm_final;
+
+ return;
+}
+
+function tale_desert_worm_final {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Nothing much else happened on that trip. When we arrived in Tulimshar, people at first didn't believe the story, of course, until we showed them the treasures and the bones. Ah, those were wonderful days...");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ "He sighs and leans back, a nostalgic look on his face.";
+
+ return;
+}
+
+function tale_desert_temple {
+ @current_story = 2;
+ if (tale_check())
+ return;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ah, that..."),
+ l("Kfahr leans back and takes a sip from his beer."),
+ l("That was many years ago, when George and I were just kids. George later became a pirate, you see; he always loved hunting for treasure. But back in those days it was all on level ground."),
+ l("George had found a treasure map somewhere... and when I say `found', I mean that in a fairly liberal sense; he always loved those maps, almost as much as the excitement of hunting for treasure."),
+ l("Anyway, that map pointed to a spot in the desert a good day's walk south of Tulimshar. So we grabbed our satchels and coats and packed food and water, and headed there in the evening."),
+ l("We walked all night. As you know, it's best not to travel during the day if you can avoid it, and we were young and energetic in those days, so that was easily avoided."),
+ l("Anyway, when the sun rose in the morning, we still hadn't found the place. So we climbed up on the nearest dune and looked all around to find it."),
+ l("But there was nothing, nothing at all. We looked and looked – and suddenly George screamed: While we weren't paying attention to nearby things, scorpions had crept up on us!"),
+ l("The scorpions had smelled the food we had brought and cut open our satchels, tearing our waterskins and making a mess of our food – and now that they were done with that, they were coming for us!"),
+ l("We didn't have any suitable weapons, and not much of a choice either, so we made a break for it. We ran into the desert, fast as our legs would carry us, and the scorpions after us."),
+ l("We very nearly didn't make it. There was nothing around but sand, and we had no water, no food – at least we'd had our breakfast already – and the sun kept burning, and burning, and trying to cook us alive."),
+ l("We had long lost the scorpions, but we were dry like parchment, and exhausted from all the sun and running. So we sat down in the shades of a dune and contemplated our options."),
+ l("Without water we couldn't last during the day. So our only hope was to find shelter somewhere – except that the only thing around was sand, and the mid-day sun would rob that of all shelter."),
+ l("So we resigned to continuing to search for something, anything – it was either that, or die of thirst for sure. The only problem was that we were already so thirsty and it was so bright that we couldn't see nor walk straight anymore."),
+ l("So we had barely made it to the top of the next dune when George slipped and rolled down the other side. I wanted to catch him, but I was too dizzy myself, and so I rolled after him."),
+ l("We seemed to roll down for hours, and I kept feeling dizzier and dizzier; I didn't have the strength to stop. When we arrived at the bottom, I just wanted to lie down and let the sun dry me up."),
+ l("I was being foolish, of course. You should never give up, no matter how hopeless the situation may seem. Anyway, I finally did decide to get up on my knees and look around again..."),
+ l("...and what I saw right before me, believe it or not, was a giant face of a man, carved into rock – there, in the middle of the desert, half-sunk, a shattered visage!"),
+ l("I pulled George up – I didn't have the strength to speak, but walking seemed to work – and we slowly made our way over to it. We weren't thinking much, just trying to find some shade, so we climbed into that thing's ear."),
+ l("Inside it felt moist, as if it was a real ear – not that I've climbed inside a real ear, mind you! But that feeling of cool and dampness and water was like a magical healing potion; we suddenly felt strength in our legs again."),
+ l("When we looked around, we noticed that there was a passage leading further underground, and long-spent torches on the wall. Fortunately I still had my tinderbox, so I wrapped my shirt around a torch and lighted it."),
+ l("We climbed down, and soon we heard the dripping of water – we had found an underground water-hole! More than that, we had found a gigantic underground cave, and, at the end of it, a huge portal."),
+ l("We first drenched ourselves in water – somehow managing not to douse the torch – and drank until we were ready to burst. When we had rested, we went to the portal to have a closer look."),
+ l("The portal was made out of bronze, or some similar metal, with images of snakes engraved all over. Curious as we were, we pulled the door open – it wasn't locked or barred in any way – and had a look inside."),
+ l("The passages in there were cool and dark, with a ceiling high enough to swallow the light of my torch. There were snakes, quite a few of them, but we were both quick-footed and managed to avoid them."),
+ l("There were chambers and inscriptions and more torches, but not a living being besides us and the snakes. Hmm. Though I could have sworn that some of the statues there were following us with their eyes..."),
+ l("All went well, until George stepped into a trap. A piece of ground just caved in, and if I hadn't grabbed his hand at the last second, he would have ended up on some rusty and probably poisoned spikes on the bottom..."),
+ l("But I moved too fast, and slipped, and let go of the torch to catch myself with the other hand – and the torch ended up in the bottom of the pit! Well, better the torch than George, I suppose..."),
+ l("Still, we no longer had any light. Being careless, I had gotten my tinderbox wet while we were at the water-hole, so we couldn't make another torch either."),
+ l("We had the choice between staying by our torch and watching it die, and then follow suit at the hands, or, well, fangs of the snakes, or wandering off in the dark, to be eaten by snakes someplace else.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr empties his beer, looking a bit disappointed.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Anyway, we took the latter option. We wandered through the dark, somehow barely avoiding the snakes and the traps, running into walls and hitting our heads on archways, until, suddenly, we saw something shining up ahead."),
+ l("That thing was on some kind of pedestal, and it looked like a golden tablet of sorts. We clambered towards it – the only source of light in here, the only thing that could save us – and hesitated."),
+ l("Should we just take it? This was clearly some kind of temple, so it might be something sacred. George and I argued about it for a while, until I decided to end the discussion – so I simply grabbed it: we needed light."),
+ l("At that point, a terrible grinding noise started all around us, as the pedestal began to sink into the ground. We had triggered some ancient trap!"),
+ l("Holes on the walls were opening up, and snakes began to gush out – only now did we realise that we were in a huge, opulent chamber, with gold and gems and images all around! But now it was too late for any looting; we had to run for our lives!"),
+ l("So we ran from that slithering mass, faster than we ever had! We had no idea where we were going of course, but at least we had light again..."),
+ l("Somehow we got lucky, somehow we escaped. It was evening again when we climbed out of that ear into the desert again, with only our lives and that golden tablet. We only barely made it back to Tulimshar in the morning."),
+ l("But we did have the tablet as a proof of what happened.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He grins.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That was my first real adventure, I think. Ah, those were exciting days.");
+
+ select
+ l("Wow."),
+ l("What happened to the tablet?"),
+ l("Did you go there again?"),
+ l("Zzzzzzz.....");
+ switch (@menu) {
+ case 1:
+ break;
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Well, we couldn't read it. We later sold it for a good price, to a young travelling archeologist; Doctor Nohlidge or something like that. She said that the engravings described sacrifical practices of an ancient snake cult...");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He shrugs.");
+ break;
+ case 3:
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr laughs.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Of course we tried to go there again. After seeing all that treasure, George wouldn't give up on it. We tried many times – as did others, from what I've heard – but we never found it again.");
+ break;
+ case 4:
+ close;
+ }
+
+ return;
+}
+
+function tale_hero_tulimshar {
+ @current_story = 3;
+ if (tale_check())
+ return;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ ("Yes, Hero of Tulimshar. That was many years ago, but I did save the city of Tulimshar from a deadly drought.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He grins broadly.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("And quite a feat that was, let me tell you!"),
+ l("Back in those days, there wasn't much trade with Hurnscald, and Tulimshar was dependent on its own water supply – critically dependent, even."),
+ l("Now, one day the water people drew from the wells started smelling. The smell was nauseating, and people who drank from it became violently sick."),
+ l("So the entire town was without water, except for the water reserves in the cistern. Someone had to act quickly – and of course that someone was me."),
+ l("With nothing more than a torch, some light armor and a sword, I climbed down one of the wells. It was a long climb; the wells go down fairly deep."),
+ l("I noticed that there were some holes in the walls of the wells, with hollow spaces on the sides... Hmm, that reminds me that I still have to check whether the rumors of a labyrinth underneath Tulimshar are true."),
+ l("Anyway, it took me a long time to get down, and every minute the stench was getting worse – something really bad was down there. I had to stop and tie a wet piece of cloth over my mouth so that I wouldn't inhale all of that nasty stuff."),
+ l("My torch was in an even poorer shape – whatever was making that smell had killed the flame, so I soon had to rely on the light from above to see anything."),
+ l("Finally I arrived at the water level. All Tulimshar wells dip into the same underground lake, which is on the side of a huge underground cavern. And in the midst of that cavern lay – hardly visible through the greenish mist coming from it – a Stinkewyrm!"),
+ l("Stinkewyrms are smaller cousins of dragons, but just as dangerous. They have a green, sticky skin, and, well, they stink. A lot. This one was particularly bad – it had filled up the entire cave with stinkiness!"),
+ l("I climbed down and swam to the shore. The stench was terrible; I had to hold my breath to get closer to the monster. There it was, lying on the ground, snoring, poisoning all our water! So I tried to wake it up to scare it away."),
+ l("I kicked it. I yelled at it. (Bad mistake, I got some of that stinky stuff in my lungs.) I poked at it with my sword. I even tried to poke it in the eyes, but I couldn't get that close to its mouth – that was where most of the smell was coming from."),
+ l("After a few attempts I couldn't take it anymore, so I had myself be pulled up again. It took me a while to recover and to tell the tale. We talked about what could be done, but no-one had an idea.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr takes a deep sip from his beer.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Finally, I came up with something. Stinkewyrms love that terrible stench of theirs, so what should be their natural enemy? Why, soap, of course!"),
+ l("We couldn't just dump all the soap into the underground lake, of course; the water would be undrinkable again. So we collected some of the soap, and I climbed down again with it."),
+ l("Having arrived at the bottom, I cut off the biggest of the water buckets and filled it with water – and that was a really big one, I could hardly carry it when it was full. Then I dissolved most the soap, and poured that onto the Stinkewyrm's head."),
+ l("Ah, that caught its attention! You should have seen that dragon roar, as it jumped to its feet and tried to find out who had soaped it! I rushed back to the water and made another bucket of soap water."),
+ l("But it had noticed me! And as soon as it had realized where I was, it came after me. Then it stopped, towering right before me, its stench nearly killing me, and grinned that broad, crooked-teeth dragon smile of its kind."),
+ l("Then it took a deep breath – and I realised that that was probably 'it' for me; Stinkewyrms can breathe fire like real dragons, and I didn't have the time to run back to the water."),
+ l("But when it breathed out, only a tiny little flame came out – and a lot of terrible smell that nearly knocked me off my feet."),
+ l("For you see, it had generated so much of the deadly smell around itself that even its own fire breath couldn't survive!"),
+ l("So it stared at me, mouth wide agape – the perfect opening!"),
+ l("I stormed at it and before it could even blink, it had a huge load of bubbly soap water down its throat."),
+ l("You should have heard the coughing and shaking! I swear, I thought the roof would collapse as it was jumping and choking..."),
+ l("Bubbles were coming out of its mouth, its nostrils, even its ears! The poor wyrm must have never felt so clean in its life!"),
+ l("I was out of soap, but the beast didn't know that – so I quickly grabbed another bucket and charged it again."),
+ l("And it worked! Seeing me like this again, it ran, squealing, back into the underground caves from where it must have come.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr roars with laughter and slaps his hands on the table.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("So we defeated it with hygiene! Ah, that was wonderful. After a day, the stench had worn off enough that we could drink the water again, and a week later it was almost completely gone. And of course I was the hero of the day.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr downs the rest of his beer.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("And from that day on they called me the `Hero of Tulimshar'");
+
+ return;
+}
+
+function tale_desert {
+ @current_story = 4;
+ if (tale_check())
+ return;
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr leans back, trying to find the right words to describe the desert.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("The desert... a cold and lonely place at night, and a hot and lonely place during the day.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("For someone who apparently spent most of his life in the desert, his insights sometimes seem less than profound.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("The desert is a living hell during some times of the year. Filled with black scorpions and snakes, except for the shadier areas, and mountain snakes if you go further east."),
+ l("South of Tulimshar is a fairly protected region; the nomads keep the snakes out of there and you'll find only relatively harmless monsters. But go west from there, to the beach, and it's scorpions and snakes..."),
+ l("...and east of there you find the old Hatmaker cave, now filled to the brim with snakes! Rumors have it that this was once an oasis, in centuries long gone by, but as far as I'm concerned that pit is just a dump that you best avoid."),
+ l("Go further to the east and you'll find ol' Pachua up on the mountain. He seems to have some kind of power over the mountain snakes there; they never attack him. I think he's a bit creepy, personally..."),
+ l("...but if he offers you some of his tobacco, then by all means give it a try! That stuff is amazing.");
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He laughs, then begins to cough.");
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Not terribly healthy, though, I s'pose...");
+
+ return;
+}
+
+function bone_quest {
+ if (getq(HurnscaldQuests_Kfahr) == 2) {
+ bone_quest_items;
+ return;
+ }
+
+ if (getq(HurnscaldQuests_Kfahr) > 2) {
+ bone_quest_finished;
+ return;
+ }
+
+ if (BaseLevel < 40) {
+ bone_quest_tooweak;
+ return;
+ }
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr stares at you for a moment, then nods.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You seem reasonably skilled. I think I may have something that I no longer need, but I don't want to give it to just anyone...");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He hesitates, obviously trying to make up his mind about something, then continues.");
+
+ setq HurnscaldQuests_Kfahr, 2;
+ bone_quest_items;
+
+ return;
+}
+
+function bone_quest_tooweak {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You know, little one, if you keep practicing a little and come back once you're a bit stronger, I might have something for you...");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He winks.");
+
+ return;
+}
+
+function bone_quest_items {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Bring me %d %s and %d %s to prove that you are a competent warrior, and I'll see if I have something for you.", .BLACK_STINGERS_NR, getitemlink(BlackScorpionStinger), .MUSHROOMS_NR, getitemlink(SmallMushroom));
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He grins.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l( "But while you are here... perhaps you would like to listen to another story?");
+
+ return;
+}
+
+function bone_quest_check_items {
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr eyes you with unconcealed amusement.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Welcome back! Did you bring me the things I asked for?");
+
+ select
+ l("Yes, here they are!"),
+ l("Er, what were those things again?"),
+ l("No, sorry, I didn't have the time. I'm more interested in hearing your stories."),
+ l("I forgot! Let me get them right now.");
+ switch (@menu) {
+ case 1:
+ bone_quest_final_check;
+ return;
+ case 2:
+ bone_quest_items;
+ return;
+ case 3:
+ return;
+ case 4:
+ close;
+ }
+
+ return;
+}
+
+function bone_quest_final_check {
+ if (countitem(BlackScorpionStinger) < .BLACK_STINGERS_NR) {
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("No, no... I said %d %s.", .BLACK_STINGERS_NR, getitemlink(BlackScorpionStinger));
+ if (countitem(BlackScorpionStinger) > 0)
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You will need %d more of those.", (.BLACK_STINGERS_NR - (countitem (BlackScorpionStinger))));
+ else
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You didn't bring even a single one!");
+ close;
+ }
+
+ if (countitem(SmallMushroom) < .MUSHROOMS_NR) {
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("No, no... I said %d %s.", .MUSHROOMS_NR, getitemlink(SmallMushroom));
+ if (countitem(SmallMushroom) > 0)
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You will need %d more of those.", (.MUSHROOMS_NR - (countitem (SmallMushroom))));
+ else
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You didn't bring me even a single little mushroom!");
+ close;
+ }
+
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Kfahr is delighted.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Well done, well done! Now that's what I call warrior spirit!");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He laughs, then suddenly stops, turning to you with suspicion in his eyes.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You DID get those yourself, didn't you? Not buy them or somesuch...?");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Before you can answer, he laughs and slaps you on the back again.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Ah, what am I thinking! Too many years in the desert make you a little suspicious of everyone and everything! Naah, I believe you.");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He pulls a strangely curved knife out of a side pocket and holds it up to the light. The blade is partly transparent, and looks quite sharp.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It's a bone knife, carved out of the umplex bone of a desert worm... you can probably guess which one.");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He grins broadly again, weighing the weapon.");
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("It's a little heavy, but one of the best knives you can get. Certainly beats a short sword any time of day."),
+ l("I had the nomads make me a few of them, and I hardly use them nowadays, so I think I can part with this one.");
+
+ if (countitem(BlackScorpionStinger) < .BLACK_STINGERS_NR) {
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You just had %d %s. What happened to them?", .BLACK_STINGERS_NR, getitemlink(BlackScorpionStinger));
+ if (countitem(BlackScorpionStinger) > 0)
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You will need %d more of those.",(.BLACK_STINGERS_NR - (countitem (BlackScorpionStinger))));
+ else
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You didn't bring even a single one!");
+ close;
+ }
+
+ if (countitem(SmallMushroom) < .MUSHROOMS_NR) {
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You just had %d %s. What happened to them?", .MUSHROOMS_NR, getitemlink(SmallMushroom));
+ if (countitem(SmallMushroom) > 0)
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You will need %d more of those.", (.MUSHROOMS_NR - (countitem (SmallMushroom))));
+ else
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You didn't bring me even a single little mushroom!");
+ close;
+ }
+
+ inventoryplace BoneKnife, 1;
+
+ mesc l("He hands you the knife.");
+ next;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Oh, and I think I'll keep those in return; I know someone who will trade them for antidote potions.");
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("He pockets the stingers and mushrooms.");
+
+ setq HurnscaldQuests_Kfahr, 3;
+ delitem BlackScorpionStinger, .BLACK_STINGERS_NR;
+ delitem SmallMushroom, .MUSHROOMS_NR;
+ quest_xp(.KNIFE_MAXLV, .KNIFE_QUEST_XP);
+ getitem BoneKnife, 1;
+ next;
+
+ return;
+}
+
+function bone_quest_finished {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I really don't have anything else I'd want to give away to make you stronger. Look around a bit yourself! You won't become a hero if you keep begging for help!");
+
+ return;
+}
+
+OnInit:
+
+ .BLACK_STINGERS_NR = 10;
+ .MUSHROOMS_NR = 10;
+ .SNAKE_SKINS_NR = 10;
+ .KNIFE_QUEST_XP = 50000;
+ .STINGER_QUEST_XP = 80000;
+ .KNIFE_MAXLV = getiteminfo(BoneKnife, ITEMINFO_ELV) + 20;
+ //.STINGER_MAXLV = 100;
+
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-2/ledmitz.txt b/npc/008-2-2/ledmitz.txt
new file mode 100644
index 00000000..71e72ac9
--- /dev/null
+++ b/npc/008-2-2/ledmitz.txt
@@ -0,0 +1,36 @@
+// Evol scripts.
+// Author:
+// gumi
+
+008-2-2,43,34,0 script Ledd NPC_DRINKER_ROAMINGO,{
+ // XXX: ^ I know it should be Led and Mitz but 4144 made names
+ // shorter than 4 characters illegal
+
+ deltimer("Mitz::OnTalk");
+ addtimer(rand(500, 900), "Mitz::OnTalk");
+OnTalk:
+ npctalk3(l("Ha! I'll drink muuuch mo.. more than you! Im not ooone biiit dr...dr..unk!"));
+ // TODO: add more sentences
+ // XXX: maybe instead of making them respond to a click they should just
+ // shout at each other at regular intervals?
+ end;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
+008-2-2,46,34,0 script Mitz NPC_DRINKER_MICKSHA,{
+
+ deltimer("Ledd::OnTalk");
+ addtimer(rand(500, 900), "Ledd::OnTalk");
+OnTalk:
+ npctalk3(l("I can still drink more! Better give up you... you... teelotaler! MORE BEER MELINDA!"));
+ // TODO: add more sentences
+ end;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
diff --git a/npc/008-2-2/mapflags.txt b/npc/008-2-2/mapflags.txt
new file mode 100644
index 00000000..8f90e197
--- /dev/null
+++ b/npc/008-2-2/mapflags.txt
@@ -0,0 +1 @@
+008-2-2 mapflag town
diff --git a/npc/008-2-2/melania.txt b/npc/008-2-2/melania.txt
new file mode 100644
index 00000000..e8e7aa86
--- /dev/null
+++ b/npc/008-2-2/melania.txt
@@ -0,0 +1,107 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Receptionist of Rusty Pick.
+
+008-2-2,28,27,0 script Melania NPC_AIRLIA,{
+ function accepted_room;
+ function register_room;
+ function lodge_check;
+
+ speech
+ l("Hello."),
+ l("Welcome to the Rusty Pick."),
+ l("One advice: Don't take the things those drinkers say too serious. They are sitting here and drinking all day."),
+ l("How can we serve you today?");
+
+ do
+ {
+ select
+ l("Could I lodge here for a while?"),
+ l("Nothing.");
+ mes "";
+
+ if (@menu == 1)
+ lodge_check();
+
+ } while (@menu != 2);
+ speech S_FIRST_BLANK_LINE,
+ l("I wish you a beautiful day.");
+ close;
+
+ // Check if you are booked here or somewhere else
+ function lodge_check {
+ if (INN_REGISTER == NO_INN)
+ {
+ register_room();
+ }
+ else if (INN_REGISTER == .inn)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You are already registered here."),
+ l("Go on the upper level if you want to change your room or to use it.");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("If you are registered somewhere else you will loose that reservation."),
+ l("Do you still want to lodge here?");
+
+ if (askyesno() == ASK_YES)
+ {
+ register_room();
+ }
+ }
+ return;
+ }
+
+ // Find out prices
+ function register_room {
+ .@price = lognbaselvl(100, 10);
+ .@price = .@price*12/10; // Make the price 20% higher by WildX request
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("That will be @@ E to set your respawn point", .@price),
+ l("This will remain your respawn point until set elsewhere."),
+ l("Is that okay?");
+
+ if (askyesno() == ASK_YES)
+ {
+ accepted_room(.@price);
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Come back later if you changed your mind!");
+ }
+
+ return;
+ }
+
+ // Book a room
+ function accepted_room {
+ .@price = getarg(0);
+ if (Zeny < .@price)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT, l("You don't have enough money, bring @@ E.", .@price);
+ }
+ else
+ {
+ emotion E_HAPPY;
+ Zeny -= .@price;
+ INN_REGISTER = .inn;
+ PC_IS_DEAD = false;
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I registered you on a random bed on the upper level."),
+ l("You can go upstairs and choose a different room if you want.");
+ savepoint "008-2-3", any(49, 53, 57), any(31, 35);
+ }
+ }
+
+OnInit:
+ .distance = 4;
+ .inn=RUSTYPICK_INN;
+ end;
+}
diff --git a/npc/008-2-2/melinda.txt b/npc/008-2-2/melinda.txt
new file mode 100644
index 00000000..964332ca
--- /dev/null
+++ b/npc/008-2-2/melinda.txt
@@ -0,0 +1,181 @@
+// Evol scripts.
+// Authors:
+// Toams
+// Description:
+// Melinda, Rusty Pick's waitress
+
+008-2-2,40,29,0 script Melinda#008-2-2 NPC_MELINDA,1,1,{
+
+function StartConversation {
+
+ .@tick = gettimetick(1);
+ if (.@tick > @Hurns_Rusty_Pick_WaitressTick + 10)
+ {
+ setarray .messages$[0], l("Welcome to our inn!"),
+ l("Welcome to the Rusty Pick."),
+ l("Please, have a seat."),
+ l("Lovely day, isn't it?");
+
+ .@r = rand(getarraysize(.messages$));
+ .@msg$ = .messages$[.@r];
+ npctalk3 .@msg$;
+ @Hurns_Rusty_Pick_WaitressTick = .@tick;
+ }
+ }
+
+function face_to_PC {
+ getmapxy(.@map$, .@cx, .@cy, 0);
+ @Melinda_ols_dir = .dir;
+ npc_turntoxy(.@cx, .@cy);
+
+ return;
+ }
+
+npc_pausemove;
+face_to_PC;
+mes "";
+mesn;
+mesq l("Hi, sweetie! Want a fresh beer for 90 Florin?");
+switch (select(l("Sure! [Don't tip]"),
+ l("Sure! [Tip 5 Florin]"),
+ l("Sure! [Tip 10 Florin]"),
+ l("Nah, maybe later.")))
+{
+ case 1:
+ if (Zeny < 90)
+ goto L_NoMoney;
+ getinventorylist;
+ if (@inventorylist_count == 100 && countitem("Beer") == 0)
+ goto L_TooMany;
+ Zeny -= 90;
+ getitem Beer, 1;
+ mes "";
+ mesn;
+ mesq l("Pff... Nickel nurser!");
+ goto L_Close;
+ case 2:
+ if (Zeny < 95)
+ goto L_NoMoney;
+ getinventorylist;
+ if (@inventorylist_count == 100 && countitem("Beer") == 0)
+ goto L_TooMany;
+ Zeny -= 95;
+ getitem "Beer", 1;
+ mes "";
+ mesn;
+ mesq l("Thanks for the tip!");
+ goto L_Close;
+ case 3:
+ if (Zeny < 100)
+ goto L_NoMoney;
+ getinventorylist;
+ if (@inventorylist_count == 100 && countitem("Beer") == 0)
+ goto L_TooMany;
+ Zeny -= 100;
+ getitem "Beer", 1;
+ mes "";
+ mesn;
+ mesq l("Thank you, sweetie! Want to hear a secret?");
+ switch (select(l("What is it, darling?"),
+ l("Nah, I don't feel like chatting.")))
+ {
+ case 1:
+ mes "";
+ mesn;
+ mesq l("The master bowyer in this village used to construct exceptional bows. When you want one you should go and ask him.");
+ goto L_Close;
+ case 2:
+ goto L_No;
+ }
+ goto L_Close;
+ case 4:
+ goto L_No;
+}
+
+L_NoMoney:
+ mes "";
+ mesn;
+ mesq l("You look broke. Don't think that you can dine and dash here!");
+ goto L_Close;
+
+L_No:
+ mes "";
+ mesn;
+ mesq l("Just call me when you changed your mind.");
+ goto L_Close;
+
+L_Close:
+ initnpctimer;
+ npc_resumemove;
+ close;
+
+L_TooMany:
+ mes "";
+ mesn;
+ mesq l("You don't have room for a beer!");
+ goto L_Close;
+
+OnTimer1000:
+ dographmovestep;
+
+OnTouch:
+ StartConversation;
+ end;
+
+OnInit:
+ .distance = 5;
+ .speed = 300;
+ initmovegraph "startspot", 40, 29,
+ "barkeeper", 43, 30,
+ "kfahr_r", 45, 36,
+ "kfahr_l", 43, 35,
+ "l_table_b", 36, 36,
+ "l_table_r", 38, 33,
+ "m_table_l", 39, 33,
+ "m_table_b", 41, 36,
+ "r_table_r", 46, 33,
+ "fireplace", 36, 28,
+ "firewood", 33, 28,
+ "to_basement", 52, 32,
+ "basement_entrance", 24, 25,
+ "basement_cabinet", 30,31,
+ "cabinet", 42, 28,
+ "bucket", 46, 30;
+
+
+
+ setmovegraphcmd "startspot", "firewood", 1, "dir 4; wait 5",
+ "firewood", "fireplace", 1, "dir 4; wait 3",
+ "fireplace", "startspot", 1, "dir 0; wait 10",
+
+ "startspot", "l_table_b", 1, "dir 4; wait 3",
+ "l_table_b", "l_table_r", 1, "dir 2; wait 3",
+ "l_table_r", "m_table_l", 1, "dir 6; wait 3",
+ "m_table_l", "m_table_b", 1, "dir 4; wait 3",
+ "m_table_b", "r_table_r", 1, "dir 2; wait 3",
+ "r_table_r", "bucket", 1, "dir 4; wait 1; emote 1;"
+ "wait 15; moveon",
+ "bucket", "startspot", 1, "dir 0; wait 5",
+
+ "startspot", "kfahr_r", 2, "dir 4; wait 5",
+ "kfahr_r", "barkeeper", 1, "dir 4; wait 1;"
+ "say Another round for kfahr's table.;"
+ "wait 1; say They sure are thirsty today;"
+ "wait 5; moveon",
+ "barkeeper", "kfahr_l", 1, "dir 6; wait 3;"
+ "say Cheers!;"
+ "wait 3; moveon",
+ "kfahr_l", "startspot", 1, "dir 0; wait 10",
+
+ "startspot", "to_basement", 1, "dir 4; warp 008-2-5 basement_entrance",
+ "basement_entrance", "basement_cabinet", 1, "dir 4; wait 5",
+ "basement_cabinet", "basement_entrance", 1, "dir 4; warp 008-2-2 to_basement",
+ "to_basement", "cabinet", 1, "dir 4; wait 5",
+ "cabinet", "startspot", 1, "dir 0; wait 15";
+
+
+
+
+ firstmove "wait 8";
+ initnpctimer;
+}
diff --git a/npc/008-2-2/note.txt b/npc/008-2-2/note.txt
new file mode 100644
index 00000000..a19fa50e
--- /dev/null
+++ b/npc/008-2-2/note.txt
@@ -0,0 +1,35 @@
+// Evol scripts.
+// Author:
+// gumi
+// Jesusalva
+
+008-2-2,32,28,0 script Note#Hurnscald:pub NPC_PAPER_NOTE,{
+ narrator(8,
+ l("We refuse service to anyone who:"),
+ "• " + l("Has a bubblehead"),
+ "• " + l("Is not properly shaded"),
+ "• " + l("Can't walk without stopping after every step"));
+
+ // In case you don't get the joke, know that it's a parody on Illutia.
+ mesc l("PS. You'll gain experience if you hang around here with friends. Ask Melinda for drinks and pay a round for them! - Management");
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
+
+// This is part of AFKing Experience
+008-2-2,28,33,0 script #AFKHurns NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ addtimer2(3000, "#AFKHurns::OnSpeeching");
+ end;
+
+OnSpeeching:
+ AFKLoop("#AFKHurns::OnSpeeching", "008-2-2", 33, 27, 48, 38);
+ end;
+}
+
+008-2-2,50,30,0 duplicate(#AFKHurns) #AFKHurns2 NPC_HIDDEN,1,0
diff --git a/npc/008-2-2/shop.txt b/npc/008-2-2/shop.txt
new file mode 100644
index 00000000..b3e9b798
--- /dev/null
+++ b/npc/008-2-2/shop.txt
@@ -0,0 +1,39 @@
+// Evol scripts.
+// Authors:
+// 4144
+// jesusalva
+// Reid
+// toams
+// Description:
+// Inn hidden shop.
+
+008-2-2,40,30,0 trader #Invisible008-2-2 NPC_HIDDEN,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem Beer, -1, 50;
+ sellitem Bread, -1, 50;
+ sellitem RedPlushWine, -1, 50;
+ sellitem Cheese, -1, 50;
+ sellitem CherryCake, -1, 50;
+ sellitem SmallHealing, -1, 50;
+ sellitem MaggotSlimePotion, -1, 50;
+
+ .distance = 10;
+ end;
+
+// FIXME Note: "20" doesn't means "restock 20 units".
+// It means "restock if less than 20 units are being sold".
+// Is this behavior intended? Seems like a bug.
+OnClock0000:
+OnClock0800:
+OnClock1600:
+ restoreshopitem Beer, 20;
+ restoreshopitem Bread, 20;
+ restoreshopitem RedPlushWine, 20;
+ restoreshopitem Cheese, 20;
+ restoreshopitem CherryCake, 20;
+ restoreshopitem SmallHealing, 20;
+ restoreshopitem MaggotSlimePotion, 50;
+}
diff --git a/npc/008-2-20/_import.txt b/npc/008-2-20/_import.txt
new file mode 100644
index 00000000..03f5f287
--- /dev/null
+++ b/npc/008-2-20/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-20: Forsaken Inn
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-20/_warps.txt",
+"npc/008-2-20/valia.txt",
diff --git a/npc/008-2-20/_warps.txt b/npc/008-2-20/_warps.txt
new file mode 100644
index 00000000..ce2f572a
--- /dev/null
+++ b/npc/008-2-20/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-20: Forsaken Inn warps
+008-2-20,25,32,0 warp #008-2-20_25_32 0,0,008-1,256,204
+008-2-20,36,38,0 warp #008-2-20_36_38 1,0,008-2-21,34,28
diff --git a/npc/008-2-20/valia.txt b/npc/008-2-20/valia.txt
new file mode 100644
index 00000000..d9545bf5
--- /dev/null
+++ b/npc/008-2-20/valia.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Our beloved Evil Witch Valia.
+// THIS IS A PLACEHOLDER!
+
+008-2-20,32,22,0 script Valia NPC_VALIA,{
+ speech
+ l("Hi!"),
+ l("You may remember me, I am Valia.");
+ l("Better stay away from my basement, you may end up like the poor guy down there.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-21/_import.txt b/npc/008-2-21/_import.txt
new file mode 100644
index 00000000..c5594e03
--- /dev/null
+++ b/npc/008-2-21/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-21: Forsaken Inn Basement
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-21/_mobs.txt",
+"npc/008-2-21/_warps.txt",
diff --git a/npc/008-2-21/_mobs.txt b/npc/008-2-21/_mobs.txt
new file mode 100644
index 00000000..d44662d6
--- /dev/null
+++ b/npc/008-2-21/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-21: Forsaken Inn Basement mobs
+008-2-21,25,38,2,1 monster Mana Ghost 1101,1,75000,250000
diff --git a/npc/008-2-21/_warps.txt b/npc/008-2-21/_warps.txt
new file mode 100644
index 00000000..5dd0f6f5
--- /dev/null
+++ b/npc/008-2-21/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-21: Forsaken Inn Basement warps
+008-2-21,34,26,0 warp #008-2-21_34_26 1,0,008-2-20,35,36
+008-2-21,22,43,0 warp #008-2-21_22_43 0,0,008-1,252,212
diff --git a/npc/008-2-22/_import.txt b/npc/008-2-22/_import.txt
new file mode 100644
index 00000000..3be6edbd
--- /dev/null
+++ b/npc/008-2-22/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-22: Mages Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-22/_savepoints.txt",
+"npc/008-2-22/_warps.txt",
diff --git a/npc/008-2-22/_savepoints.txt b/npc/008-2-22/_savepoints.txt
new file mode 100644
index 00000000..1cc5c220
--- /dev/null
+++ b/npc/008-2-22/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-22: Mages Hut saves
+008-2-22,26,31,0 script #save_008-2-22_26_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-22/_warps.txt b/npc/008-2-22/_warps.txt
new file mode 100644
index 00000000..c45099dc
--- /dev/null
+++ b/npc/008-2-22/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-22: Mages Hut warps
+008-2-22,30,35,0 warp #008-2-22_30_35 0,0,008-1,122,115
diff --git a/npc/008-2-23/_import.txt b/npc/008-2-23/_import.txt
new file mode 100644
index 00000000..feb70f60
--- /dev/null
+++ b/npc/008-2-23/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-23: Mouboo Farm
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-23/_warps.txt",
diff --git a/npc/008-2-23/_warps.txt b/npc/008-2-23/_warps.txt
new file mode 100644
index 00000000..4bd4b6ee
--- /dev/null
+++ b/npc/008-2-23/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-23: Mouboo Farm warps
+008-2-23,52,40,0 warp #008-2-23_52_40 0,0,008-1,71,129
diff --git a/npc/008-2-24/_import.txt b/npc/008-2-24/_import.txt
new file mode 100644
index 00000000..808bd398
--- /dev/null
+++ b/npc/008-2-24/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-24: Dimond's Cove Ground Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-24/_warps.txt",
+"npc/008-2-24/chef.txt",
+"npc/008-2-24/troupe-leader.txt",
diff --git a/npc/008-2-24/_warps.txt b/npc/008-2-24/_warps.txt
new file mode 100644
index 00000000..c72b102d
--- /dev/null
+++ b/npc/008-2-24/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-24: Dimond's Cove Ground Floor warps
+008-2-24,27,24,0 warp #008-2-24_27_24 0,0,008-2-27,44,28
+008-2-24,40,27,0 warp #008-2-24_40_27 2,0,008-2-25,41,27
+008-2-24,32,46,0 warp #008-2-24_32_46 0,0,008-1,106,222
diff --git a/npc/008-2-24/chef.txt b/npc/008-2-24/chef.txt
new file mode 100644
index 00000000..a2b8b618
--- /dev/null
+++ b/npc/008-2-24/chef.txt
@@ -0,0 +1,269 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// The nameless chef of Dimond's Cove, lover of pickled beets.
+
+008-2-24,30,25,0 script Chef#Dimond NPC_CHEF_LEGACY,{
+ function deliverFish;
+ function useYourHead;
+ function reminderReid;
+ function recipeBad;
+ function reminderBakery;
+ function heyDiabetes;
+ function reminderSalad;
+ function deliverSalad;
+ mesn;
+ mesq l("I'm too busy right now to talk.");
+ // TODO: Kadiya Quest
+ // TODO: Pickled Beets Quest
+ // (Probably can be mashed together in deliverFish?)
+ switch (getq(General_Cooking)) {
+ case 3:
+ deliverFish();
+ break;
+ case 4:
+ useYourHead();
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ reminderReid();
+ break;
+ case 10:
+ recipeBad();
+ break;
+ case 11:
+ case 12:
+ case 13:
+ reminderBakery();
+ break;
+ case 14:
+ heyDiabetes();
+ break;
+ case 15:
+ case 16:
+ reminderSalad();
+ break;
+ case 17:
+ deliverSalad();
+ break;
+ }
+ close;
+
+function deliverFish {
+ next;
+ mesn;
+ mesq l("If you have any business with me, get it over already.");
+ mes "";
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+
+ .@id = requestitem();
+
+ // If ID is invalid
+ if (.@id < 1)
+ return;
+
+ // If there's not enough items, it is bound, it cannot be traded/dropped/sold, etc.
+ if (countitem(.@id) < 2 || checkbound(.@id)) {
+ mesc l("You need at least two units of this item for the Chef.");
+ close;
+ }
+
+ // Now now now, what have you given to the Chef...?
+ switch (.@id) {
+ case CommonCarp:
+ case GrassCarp:
+ case Codfish:
+ case Tuna:
+ case Trout:
+ case Salmon:
+ mesn;
+ mesq l("...I hate you.");
+ break;
+ // Other Quests
+ //case OrangeCupcake:
+ //case ChocolateCake:
+ // Fun items and Easter Eggs
+ //case PickledBeets:
+ case Beer:
+ mesn;
+ mesq l("Wha - I am not a drunkard, and anyone who says that is lying!");
+ break;
+ case EasterBasket:
+ mesn;
+ mesq l("Easter event is over, no pickled beets for you!");
+ break;
+ // Default
+ default:
+ mesn;
+ mesq l("What do you expect me to do with this? GO AWAY!");
+ return;
+ }
+ delitem .@id, 2;
+ getexp 1000, 0;
+ setq1 General_Cooking, 4;
+ next;
+ mesn;
+ mesq l("I'm tired of cooking fish all the time. I used to bake Orange Cupcakes and pickled beets!");
+ next;
+ mesn;
+ mesq l("But since that damned Oscar stopped supplying me fruits, I'm trapped in fish-cooking.");
+ useYourHead();
+ return;
+}
+
+function useYourHead {
+ next;
+ mesn;
+ mesq l("I'm too busy to cook the %s but I won't teach you the recipe. I still need to make a living after all.", getitemlink(SeafoodPlate));
+ next;
+ select
+ l("There is no solution for your dilemma."),
+ l("Maybe if you had a recipe which doesn't needs fruits?"),
+ l("Maybe if I convinced Oscar to supply you fruits again?");
+ mes "";
+ if (@menu == 1) {
+ return;
+ } else if (@menu == 2) {
+ mesn;
+ mesq l("Hmpf! It would need to be worth of Dimond's name! I won't accept a lame %s.", getitemlink(SailorStew));
+ setq1 General_Cooking, 5;
+ reminderReid();
+ } else {
+ mesn;
+ mesq l("Hah! In case you didn't noticed, Oscar is a mage. A rather good one.");
+ next;
+ mesn;
+ mesq l("He, however, used magic to improve his crops, and the Brotherhood got wind of that. Some stuff about \"transgenic\" or whatever.");
+ next;
+ mesn;
+ mesq l("I mean, this is a magical world, isn't it?! That makes no sense. He probably angered some corrupt officer or whatever.");
+ next;
+ mesn;
+ mesq l("Maybe you can help him get back his job and stuff, I think the whole town would thank you for that. But I need some more immediate solution, not empty idealist promises.");
+ // TODO: Finish this path so players doesn't have to learn Squirrel Stew
+ }
+ return;
+}
+
+function reminderReid {
+ next;
+ mesn;
+ mesq l("You know what, I've heard the chef from Reid's Inn used to be a great chef when they were alive.");
+ next;
+ mesn;
+ mesq l("Maybe they know some great recipe from the parallel dimensions which doesn't need fruits.");
+ next;
+ mesn;
+ mesq l("Learn and share that with me, and only then, I'll teach you the %s recipe for Yannika.", getitemlink(SeafoodPlate));
+ return;
+}
+
+/* TODO: “The Cook starts too cook the recipe from Reid's Inn the player gave him but the squirrel he uses is still alive and bites him. He does not want to cook anymore wildlife. Fish stinks, Squirrels bite etc. ... and he does not give away his fish recipe.” */
+function recipeBad {
+ .@recipe=(getq2(General_Cooking) == CARNIVOROUS ? MoubooStew : SquirrelStew);
+ mesn;
+ mesq l("You know what, I've heard the chef from Reid's Inn used to be a great chef when they were alive.");
+ next;
+ mesn;
+ mesq l("Maybe they know some great recipe from the parallel dimensions which doesn't need fruits.");
+ next;
+ mesn;
+ mesq l("Learn and share that with me, and only then, I'll teach you the %s recipe for Yannika.", getitemlink(SeafoodPlate));
+ next;
+ select
+ l("He teached me the %s recipe.", getitemname(.@recipe)),
+ l("Alright, I'll be right back.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("%s? What is even a %s? Are you trying to poison my customers?!", getitemlink(.@recipe), getitemlink(.@recipe));
+ next;
+ mesn;
+ mesq l("Bah! I should have known better. Of course you would only find weird people in Golbenez's fantasy inn.");
+ next;
+ mesn;
+ mesc l("%s sighs.", .name$);
+ mesq l("You know what? Maybe I should make some dessert instead. It is perfect, who doesn't likes desserts, anyway?");
+ // Well, Ms. Dimond in Moubootaur Legends, who got overweight maybe...?
+ next;
+ mesn;
+ mesq l("Tulimshar has a great bakery - learn their secrets and share with me something sweet and nice. Go already!");
+ setq1 General_Cooking, 11;
+ return;
+}
+
+function reminderBakery {
+ next;
+ mesn;
+ mesc l("%s sighs.", .name$);
+ mesq l("You know what? Maybe I should make some dessert instead. It is perfect, who doesn't likes desserts, anyway?");
+ next;
+ mesn;
+ mesq l("Tulimshar has a great bakery - learn their secrets and share with me something sweet and nice. Go already!");
+ return;
+}
+
+function heyDiabetes {
+ mesn;
+ mesq l("%s, where have you been?! I looked for you everywhere in Hurnscald and couldn't find you!", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("I remembered I have diabetes, so I wouldn't be able to taste the food! So sweets might be a bad idea!");
+ next;
+ mesn;
+ mesq l("Also, the doctor told Dimond to lose weight, so salads might be a better choice.");
+ next;
+ select
+ l("WHAT?! I even got a Donut recipe!!"),
+ l("Okay... Where can I find salad recipe?"),
+ l("Can't you do it yourself?!");
+ mes "";
+ if (@menu == 3) {
+ mesn;
+ mesq l("Sure I could, but who wants the %s recipe is you, not me. So get to work!", getitemlink(SeafoodPlate));
+ next;
+ }
+ mesn;
+ mesq l("Well, you can bake sweets for yourself, they don't require a Plate anyway. As for salad...");
+ next;
+ mesn;
+ mesq l("I honestly don't know. I mean, we usually export healthy food to Tulimshar; People here aren't so healthy in general.");
+ next;
+ mesn;
+ mesq l("Not sure who in Tulimshar would have money to import that much lettuce and such, but good luck figuring it out!");
+ setq1 General_Cooking, 15;
+ return;
+}
+
+function reminderSalad {
+ mesn;
+ mesq l("Not sure who in Tulimshar would have money to import that much lettuce and such, but good luck figuring it out!");
+ next;
+ mesn;
+ mesq l("Bring me Salad, the healthiest of all foods!");
+ return;
+}
+
+function deliverSalad {
+ mesn;
+ mesq l("What is that...? Salad! You did it!! Give me the recipe!");
+ next;
+ mesn strcharinfo(0);
+ mesc l("You give the recipe to the Chef.");
+ next;
+ mesn;
+ mesq l("Here, I'll now teach you the %s recipe. Don't share it with anyone, and good luck cooking one for Yannika! Yoo-hoo!", getitemlink(SeafoodPlate));
+ RECIPES[CraftSeafoodPlate]=true;
+ setq1 General_Cooking, 18;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-24/troupe-leader.txt b/npc/008-2-24/troupe-leader.txt
new file mode 100644
index 00000000..3311e567
--- /dev/null
+++ b/npc/008-2-24/troupe-leader.txt
@@ -0,0 +1,119 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-2-24,41,39,0 script Troupe Leader NPC_DIMOND,{
+
+ function nohmask_question {
+ // XXX: shouldn't the player ask a question before she replies Yes? this feels too abrupt
+ speech(4,
+ l("Yes, a mask was stolen from us the last night we were in Hurnscald."));
+
+ selectd(
+ l("Any ideas on who might have taken it?"),
+ l("Are you sure one of your troupe members didn't hide it and commit those robberies?"),
+ l("Hmm..."));
+
+ switch (@menu)
+ {
+ case 1:
+ speech(
+ l("Hm..."),
+ l("I did see an old man hang out near the theater after our last show."));
+ close2;
+ setq(.quest_inspector, 6);
+ close;
+
+ case 2:
+ speech(
+ l("I am absolutely positive."),
+ l("None of my troupe have left the city since we got here."),
+ l("Good day!"));
+ close;
+ }
+
+ closeclientdialog();
+ close;
+ }
+
+ function nohmask_found {
+ // XXX: shouldn't the player say "I found your mask" before the npc says thanks?
+ speech(4,
+ l("Thank you for finding the mask."),
+ l("You did such a good job, you should keep it."));
+
+ if (checkweight(.reward_item, 1) != true)
+ {
+ speech(8,
+ l("It seems you can't carry it right now..."));
+ close;
+ }
+
+ setq(.quest_inspector, 15);
+ quest_xp(.maxLevel, .reward_exp);
+ getitem(.reward_item, 1);
+
+ speech(
+ l("We don't need it anymore."),
+ l("We're doing different shows here."));
+ close;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_inspector))
+ {
+ case 5: nohmask_question; break;
+ // XXX: shouldn't it have an in-between state where it says good luck or something?
+ case 14: nohmask_found; break;
+ // XXX: shouldn't it have a "completed" state where it says thanks, come back any time?
+ }
+
+ // initial intro
+ speech(
+ l("Hello."),
+ l("I'm the leader of a traveling theater troupe."),
+ l("We'll be staying here in Tulimshar for a while."));
+ close;
+
+OnInit:
+ .reward_item = NohMask;
+ .reward_exp = 1500;
+ .maxLevel = 60;
+
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-2-25/_import.txt b/npc/008-2-25/_import.txt
new file mode 100644
index 00000000..02e36d2e
--- /dev/null
+++ b/npc/008-2-25/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-25: Dimond's Cove Second Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-25/_warps.txt",
diff --git a/npc/008-2-25/_warps.txt b/npc/008-2-25/_warps.txt
new file mode 100644
index 00000000..d7199084
--- /dev/null
+++ b/npc/008-2-25/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-25: Dimond's Cove Second Floor warps
+008-2-25,25,27,0 warp #008-2-25_25_27 2,0,008-2-26,23,25
+008-2-25,41,29,0 warp #008-2-25_41_29 2,0,008-2-24,40,30
diff --git a/npc/008-2-26/_import.txt b/npc/008-2-26/_import.txt
new file mode 100644
index 00000000..9b4f3a94
--- /dev/null
+++ b/npc/008-2-26/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-26: Dimond's Cove Third Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-26/_warps.txt",
diff --git a/npc/008-2-26/_warps.txt b/npc/008-2-26/_warps.txt
new file mode 100644
index 00000000..e370bcef
--- /dev/null
+++ b/npc/008-2-26/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-26: Dimond's Cove Third Floor warps
+008-2-26,24,27,0 warp #008-2-26_24_27 1,0,008-2-25,25,29
diff --git a/npc/008-2-27/_import.txt b/npc/008-2-27/_import.txt
new file mode 100644
index 00000000..98ec740f
--- /dev/null
+++ b/npc/008-2-27/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-27: Dimond's Cove Cellar
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-27/_warps.txt",
diff --git a/npc/008-2-27/_warps.txt b/npc/008-2-27/_warps.txt
new file mode 100644
index 00000000..350010dc
--- /dev/null
+++ b/npc/008-2-27/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-27: Dimond's Cove Cellar warps
+008-2-27,45,28,0 warp #008-2-27_45_28 0,1,008-2-24,28,24
diff --git a/npc/008-2-28/_import.txt b/npc/008-2-28/_import.txt
new file mode 100644
index 00000000..0510c48c
--- /dev/null
+++ b/npc/008-2-28/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-28: Big House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-28/_warps.txt",
diff --git a/npc/008-2-28/_warps.txt b/npc/008-2-28/_warps.txt
new file mode 100644
index 00000000..c83ed168
--- /dev/null
+++ b/npc/008-2-28/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-28: Big House warps
+008-2-28,25,32,0 warp #008-2-28_25_32 0,0,008-1,257,131
diff --git a/npc/008-2-29/_import.txt b/npc/008-2-29/_import.txt
new file mode 100644
index 00000000..d708d657
--- /dev/null
+++ b/npc/008-2-29/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-29: Pool House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-29/_warps.txt",
diff --git a/npc/008-2-29/_warps.txt b/npc/008-2-29/_warps.txt
new file mode 100644
index 00000000..40d34697
--- /dev/null
+++ b/npc/008-2-29/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-29: Pool House warps
+008-2-29,37,24,0 warp #008-2-29_37_24 0,0,008-1,234,131
diff --git a/npc/008-2-3/_import.txt b/npc/008-2-3/_import.txt
new file mode 100644
index 00000000..69f68a67
--- /dev/null
+++ b/npc/008-2-3/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-3: The Rusty Pick
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-3/_savepoints.txt",
+"npc/008-2-3/_warps.txt",
+"npc/008-2-3/mapflags.txt",
diff --git a/npc/008-2-3/_savepoints.txt b/npc/008-2-3/_savepoints.txt
new file mode 100644
index 00000000..4e70dc2e
--- /dev/null
+++ b/npc/008-2-3/_savepoints.txt
@@ -0,0 +1,106 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-3: The Rusty Pick saves
+008-2-3,61,31,0 script #save_008-2-3_61_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,60,35,0 script #save_008-2-3_60_35 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,57,31,0 script #save_008-2-3_57_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,57,35,0 script #save_008-2-3_57_35 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,53,35,0 script #save_008-2-3_53_35 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,53,31,0 script #save_008-2-3_53_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,49,31,0 script #save_008-2-3_49_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+008-2-3,49,35,0 script #save_008-2-3_49_35 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, RUSTYPICK_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-3/_warps.txt b/npc/008-2-3/_warps.txt
new file mode 100644
index 00000000..3233aa46
--- /dev/null
+++ b/npc/008-2-3/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-3: The Rusty Pick warps
+008-2-3,67,29,0 warp #008-2-3_67_29 1,0,008-2-2,51,29
diff --git a/npc/008-2-3/mapflags.txt b/npc/008-2-3/mapflags.txt
new file mode 100644
index 00000000..947a2df3
--- /dev/null
+++ b/npc/008-2-3/mapflags.txt
@@ -0,0 +1 @@
+008-2-3 mapflag town
diff --git a/npc/008-2-30/_import.txt b/npc/008-2-30/_import.txt
new file mode 100644
index 00000000..df7088b9
--- /dev/null
+++ b/npc/008-2-30/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-30: Hurns Farmhouse
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-30/_warps.txt",
diff --git a/npc/008-2-30/_warps.txt b/npc/008-2-30/_warps.txt
new file mode 100644
index 00000000..8afbf1e8
--- /dev/null
+++ b/npc/008-2-30/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-30: Hurns Farmhouse warps
+008-2-30,52,40,0 warp #008-2-30_52_40 0,0,008-1,287,134
diff --git a/npc/008-2-31/_import.txt b/npc/008-2-31/_import.txt
new file mode 100644
index 00000000..7f013b3e
--- /dev/null
+++ b/npc/008-2-31/_import.txt
@@ -0,0 +1,3 @@
+// Map 008-2-31: Kyttys Home
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-31/_warps.txt",
diff --git a/npc/008-2-31/_warps.txt b/npc/008-2-31/_warps.txt
new file mode 100644
index 00000000..82846783
--- /dev/null
+++ b/npc/008-2-31/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-31: Kyttys Home warps
+008-2-31,28,25,0 warp #008-2-31_28_25 0,0,008-1,288,125
diff --git a/npc/008-2-32/_import.txt b/npc/008-2-32/_import.txt
new file mode 100644
index 00000000..ba8aa591
--- /dev/null
+++ b/npc/008-2-32/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-32: Merchant House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-32/_warps.txt",
+"npc/008-2-32/thamas.txt",
diff --git a/npc/008-2-32/_warps.txt b/npc/008-2-32/_warps.txt
new file mode 100644
index 00000000..99f22bd8
--- /dev/null
+++ b/npc/008-2-32/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-32: Merchant House warps
+008-2-32,40,38,0 warp #008-2-32_40_38 0,0,008-1-1,51,58
diff --git a/npc/008-2-32/thamas.txt b/npc/008-2-32/thamas.txt
new file mode 100644
index 00000000..2a338ef1
--- /dev/null
+++ b/npc/008-2-32/thamas.txt
@@ -0,0 +1,83 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Thamas the soldier.
+// THIS IS A PLACEHOLDER!
+
+008-2-32,36,31,0 script Thamas NPC_THAMAS,{
+ speech
+ l("Hi there."),
+ l("I am a legion soldier who never talks much, until Jesusalva or WildX puts words in my mouth."),
+ l("However, I can't wait to see animals, er, uncivilized people of these woodlands."),
+ l("Meh, I'm still with stomach ache due to that stew Morcant is used to cook. Like as I'm not enough nervous about the special mission I've been assigned to."),
+ //l("I bet he uses squirrels to make that damn stew. Bleah."),
+ l("Until then, let me be quiet. Talk to you later.");
+ next;
+ select
+ l("Okay, sorry for disturbing."),
+ l("But you said you remember me!"),
+ l("What do you think about this stew?"),
+ l("Where are you from, though? You have an odd... behavior."),
+ l("What is a legion soldier even doing here? A special mission?"),
+ l("Who are Jesusalva and WildX?");
+ mes "";
+ switch (@menu)
+ {
+ case 2:
+ mesn;
+ mesq l("And I do. We were on the same ship a few times.");
+ next;
+ mesn;
+ mesq l("You stood out and I stayed on my corner. That's all.");
+ next;
+ mesn;
+ mesq l("Stop making questions which make no sense...");
+ break;
+ case 3:
+ mesn;
+ mesq l("Eh? It is okay, I guess.");
+ next;
+ mesn;
+ mesq l("I hear if you get a recipe book, you could cook things yourself.");
+ next;
+ mesn;
+ mesq l("Maybe someone in Hurnscald makes these books. I don't really care.");
+ next;
+ mesn;
+ mesq l("Stop making questions which make no sense...");
+ break;
+ case 4:
+ mesn;
+ mesq l("I'm from Esperia.");
+ next;
+ mesn;
+ mesq l("It would be tiring to describe the wonders of my hometown.");
+ next;
+ mesn;
+ mesq l("Why don't you look an article about it on this [%s|tour guide%s], instead?", "@@https://wiki.themanaworld.org/index.php/Esperia", "@@");
+ next;
+ mesn;
+ mesq l("Stop making questions which make no sense...");
+ break;
+ case 5:
+ mesn;
+ mesq l("I can't tell you. Captain Hal is in charge so ask him if you really care.");
+ next;
+ mesq l("You can find him to the clifftop behind Morcant's house.");
+ if(!getq(General_CptHal)) setq(General_CptHal,1); // Start Captain Hal quest
+ break;
+ case 6:
+ mesn;
+ mesq l("Honestly? I don't know.");
+ next;
+ mesn;
+ mesq l("Stop making questions which make no sense...");
+ break;
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-4/_import.txt b/npc/008-2-4/_import.txt
new file mode 100644
index 00000000..826aa135
--- /dev/null
+++ b/npc/008-2-4/_import.txt
@@ -0,0 +1,7 @@
+// Map 008-2-4: The Rusty Pick
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-4/_savepoints.txt",
+"npc/008-2-4/_warps.txt",
+"npc/008-2-4/bernard.txt",
+"npc/008-2-4/mapflags.txt",
+"npc/008-2-4/olana.txt",
diff --git a/npc/008-2-4/_savepoints.txt b/npc/008-2-4/_savepoints.txt
new file mode 100644
index 00000000..0129971e
--- /dev/null
+++ b/npc/008-2-4/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-4: The Rusty Pick saves
+008-2-4,25,27,0 script #save_008-2-4_25_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-4/_warps.txt b/npc/008-2-4/_warps.txt
new file mode 100644
index 00000000..2d8336f7
--- /dev/null
+++ b/npc/008-2-4/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-4: The Rusty Pick warps
+008-2-4,44,28,0 warp #008-2-4_44_28 0,0,008-2-2,25,29
diff --git a/npc/008-2-4/bernard.txt b/npc/008-2-4/bernard.txt
new file mode 100644
index 00000000..a7cd2382
--- /dev/null
+++ b/npc/008-2-4/bernard.txt
@@ -0,0 +1,222 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - bernard wants roasted maggot
+// [1] 3 - brought maggot
+// [1] 4 - bernard wants maggot slime
+// [1] 5 - brought maggot slime
+// [1] 6 - mikhail needs maggot slime
+// [1] 7 - brought maggot slime
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// Bernard wants to make a maggot slime soup
+
+008-2-4,34,29,0 script Bernard NPC_BERNARD,{
+
+ if (BaseLevel < .min_level)
+ {
+ npctalk3 generic(16 | 32);
+ end;
+ }
+
+ function soup_intro {
+ if (rand(2) == 1)
+ {
+ speech 4,
+ l("The fields are crawling with maggots."),
+ l("Where is Mikhail?"),
+ l("What is taking them so long?"),
+ l("Could I ask a favor of you?");
+ }
+ else
+ {
+ speech 4,
+ l("The taste of maggots in soup is... unforgettable."),
+ l("They taste simply divine!"),
+ l("I sent someone to kill me some maggots and they have yet to return."),
+ l("Would you help me kill some?");
+ }
+
+ if (selectd(l("Yes."), l("No.")) == 2)
+ {
+ return;
+ }
+
+ if (rand(2) == 1)
+ {
+ speech 4,
+ l("Great!"),
+ l("I need a %s for my soup.", getitemlink(.first_item));
+ }
+ else
+ {
+ speech 4,
+ l("Bring me a %s.", getitemlink(.first_item)),
+ l("I'll give you something if you do.");
+ }
+
+ speech 8,
+ l("Please bring it to me!");
+
+ setq .quest, 2;
+ close;
+ }
+
+ function soup_reminder_roasted {
+ speech
+ l("Oh, please hurry and bring me a %s.", getitemlink(.first_item)),
+ l("I'm yearning for maggot soup!");
+ close;
+ }
+
+ function soup_no_room {
+ speech 1 | 8,
+ "...",
+ l("It seems you don't have room for my reward."),
+ l("I'll wait until you do.");
+ close;
+ }
+
+ function soup_reward_roasted {
+ speech 4,
+ l("Oooh, perfect! It's perfect!"),
+ l("You brought me my %s!", getitemlink(.first_item)),
+ l("Here, have some %s for your troubles.",
+ getitemlink(.first_reward_item));
+
+ if (checkweight(.first_reward_item, .first_reward_amount) != true)
+ soup_no_room;
+
+ if (countitem(.first_item) < 1)
+ close;
+
+ delitem .first_item, 1;
+ quest_item(.maxLevel, .first_reward_item, .first_reward_amount);
+ quest_xp(.maxLevel, .first_reward_exp);
+ setq .quest, 3;
+
+ speech 8,
+ l("Now let's see...");
+ close;
+ }
+
+ function soup_ask_slime {
+ speech
+ l("Thank you so much!"),
+ l("But... something is missing to make the soup creamy."),
+ l("I need %d %s for that.",
+ .second_item_qty, getitemlink(.second_item)),
+ l("Bring them to me, and I'll give you something nice.");
+
+ setq .quest, 4;
+ close;
+ }
+
+ function soup_reminder_slime {
+ speech
+ l("Please do hurry and bring me %d %s, so I can finish my soup!",
+ .second_item_qty, getitemlink(.second_item));
+ close;
+ }
+
+ function soup_reward_slime {
+ speech
+ l("Nice!"),
+ l("They're perfect, just perfect!"),
+ l("You brought me the %d %s!",
+ .second_item_qty, getitemlink(.second_item)),
+ l("Here, have some %s as reward.",
+ getitemlink(.second_reward_item));
+
+ if (checkweight(.second_reward_item, .second_reward_amount) != true)
+ soup_no_room;
+
+ if (countitem(.second_item) < .second_item_qty)
+ close;
+
+ delitem .second_item, .second_item_qty;
+ quest_item(.maxLevel, .second_reward_item, .second_reward_amount);
+ quest_xp(.maxLevel, .second_reward_exp);
+ setq .quest, 5;
+
+ close;
+ }
+
+ function soup_thanks_slime {
+ speech
+ l("I didn't mention it before, but I also put beer in my soup."),
+ l("I hope you like beer as much as I do, because, you see..."),
+ l("Beer is life!");
+ close;
+ }
+
+ function soup_thanks_mikhail {
+ speech
+ l("My help, Mikhail, finally returned with the slimes I needed."),
+ l("I wonder what took him so long?");
+ close;
+ }
+
+
+ // OnTalk:
+ switch (getq(.quest))
+ {
+ case 0:
+ case 1: soup_intro; break;
+ case 2:
+ if (countitem(.first_item) < 1)
+ soup_reminder_roasted;
+ else
+ soup_reward_roasted;
+ break;
+ case 3: soup_ask_slime; break;
+ case 4:
+ if (countitem(.second_item) < .second_item_qty)
+ soup_reminder_slime;
+ else
+ soup_reward_slime;
+ break;
+ case 5:
+ case 6: soup_thanks_slime; break;
+ default: soup_thanks_mikhail;
+ }
+
+ closeclientdialog();
+ close;
+
+OnPCLoginEvent:
+OnPCBaseLvUpEvent:
+ if (BaseLevel >= .min_level && getq(.quest) < 1)
+ {
+ setq .quest, 1; // allow the player to do the quest
+ dispbottom l("New quest available: %s (level %d+)",
+ getquestlink(.quest), .min_level); // XXX: requires new manaplus versions, maybe show a different message for old versions?
+ }
+ end;
+
+OnInit:
+ .min_level = 10; // min level to do the quest
+ .maxLevel = 30;
+
+ .first_item = RoastedMaggot;
+ .first_reward_item = CherryCake;
+ .first_reward_amount = 5;
+ .first_reward_exp = 100;
+
+ .second_item = MaggotSlime;
+ .second_item_qty = 3;
+ .second_reward_item = Beer;
+ .second_reward_amount = 3;
+ .second_reward_exp = 100;
+
+ .quest = HurnscaldQuests_Soup;
+ .quest_debug = .quest;
+ .distance = 3;
+
+ end;
+}
diff --git a/npc/008-2-4/mapflags.txt b/npc/008-2-4/mapflags.txt
new file mode 100644
index 00000000..cd86a1e4
--- /dev/null
+++ b/npc/008-2-4/mapflags.txt
@@ -0,0 +1 @@
+008-2-4 mapflag town
diff --git a/npc/008-2-4/olana.txt b/npc/008-2-4/olana.txt
new file mode 100644
index 00000000..4c42f599
--- /dev/null
+++ b/npc/008-2-4/olana.txt
@@ -0,0 +1,321 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Alastrim
+// Ali-g
+// Dark Mage
+// Description:
+// Olana, the old woman who is looking for her daughter Rossy and Juliet.
+// HurnscaldQuests_Rossy
+// 0 - Quest Not Assigned
+// 1 - Asked to look for Rossy
+
+
+008-2-4,30,28,0 script Olana NPC_OLANA,{
+ function olanaIntro;
+ function olanaIntroDone;
+ function olanaRossyLie;
+ function olanaDeliverBerries;
+ function olanaGetLetter;
+ function olanaRossyGoodGirl;
+ function olanaRossyBadMom;
+ function olanaRossyHappy;
+ .@q=getq(HurnscaldQuests_Rossy);
+ if (BaseLevel < .minLevel)
+ .@q = -1; // Hard Reset
+ mesn;
+ mesq l("Oh, a traveler. Welcome.");
+ next;
+ switch (.@q) {
+ case 0:
+ olanaIntro();
+ break;
+ case 1:
+ olanaIntroDone();
+ break;
+ case 2:
+ olanaRossyLie();
+ break;
+ case 3:
+ mesc l("%s smiles at you, but she still seems preoccupied.", .name$);
+ next;
+ mesc l("Rossy was collecting fruits, right? Maybe she has some idea on how to cheer her mother up?");
+ break;
+ case 4:
+ olanaDeliverBerries();
+ break;
+ case 5:
+ olanaGetLetter();
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ mesn;
+ mesq l("Please bring Hocus' letter to my daughter as fast as you can.");
+ break;
+ case 10:
+ olanaRossyGoodGirl();
+ break;
+ case 11:
+ mesn;
+ mesc l("%s says absently-minded, while staring at a portrait of her daughters, Rossy and Juliet:");
+ mesq l("Could you do me a favor? Could you bring her %d %s? I am sure she will love them!", 15, getitemlink(ARedRose));
+ break;
+ case 12:
+ olanaRossyBadMom();
+ break;
+ case 13:
+ mesn;
+ mesq l("Please, tell Rossy I am really sorry and buy her Red Tulips instead, the same amount - %d, her age.", 15);
+ break;
+ case 14:
+ olanaRossyHappy();
+ break;
+ case 15:
+ case 16:
+ mesn;
+ mesq l("Where is Juliet? I want to know where she is! Please find her, %s!", strcharinfo(0));
+ break;
+ case 17:
+ mesn;
+ mesq l("Juliet got home sound and safe thanks to you, %s. I'll be eternally grateful.", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("Rossy and Juliet are out there, playing again. Please, feel free to play with them or to come here for a cup of water.");
+ break;
+ default:
+ speech
+ l("Did you see my daughters Rossy and Juliet, by chance?"),
+ l("She wasn't at home for two days now. I worry about her!"),
+ l("If you see her, please tell her to come home.");
+ }
+ close;
+
+function olanaIntro {
+ mesn;
+ mesq l("This is a private room from the Rusty Pick. You see, my father owns this inn.");
+ next;
+ mesn;
+ mesq l("I moved to Tulimshar so my daughters – Rossy and Juliet – could learn magic, but we come back to Hurnscald on occasion.");
+ next;
+ mesn;
+ mesc l("Olana suddenly looks very pale and starts to shiver.");
+ mesq l("Which reminds me - I let my two lovely girls play in the woods nearby but they haven't come back yet!");
+ next;
+ mesn;
+ mesq l("These forests are not safe; I am afraid they might have wandered in the swamps by accident.");
+ next;
+ mesn;
+ mesq l("Could you pretty please see if they're fine? I can book you this inn for a night after that.");
+ next;
+ if (askyesno() == ASK_NO) {
+ mesn;
+ mesq l("Well, you *do* look weak, I guess I would get worried if you went after them and ended up lost and on the swamps.");
+ next;
+ mesn;
+ mesq l("But if you change your mind, please, call me again.");
+ return;
+ }
+ mesn;
+ mesq l("Excellent! I am counting on you!");
+ setq HurnscaldQuests_Rossy, 1;
+ return;
+}
+
+function olanaIntroDone {
+ mesn;
+ mesq l("My daughters – Rossy and Juliet – went to play in the woods but haven't come back yet.");
+ next;
+ mesn;
+ mesq l("Could you pretty please see if they're fine? I can book you this inn for a night after that.");
+ return;
+}
+
+function olanaRossyLie {
+ mesn;
+ mesq l("Have you found my daughters yet? %%i");
+ next;
+ select
+ l("No, sorry, I'll keep looking."),
+ l("I saw Rossy, she is fine."),
+ l("Yes, a snail attacked them.");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("Please do, I'm worried about them....");
+ return;
+ }
+ if (@menu == 3) {
+ mesn;
+ mesq l("Oh noes!!!!");
+ next;
+ mesc l("%s faints.", .name$);
+ mesc l("Maybe we could have told her that in a better way.");
+ return;
+ }
+ mesn;
+ mesq l("Oh you did? That's good. I'm relieved. But what about Juliet?");
+ next;
+ select
+ l("I haven't found Juliet yet, sorry."),
+ l("Well, Rossy told both of them were fine...");
+ mes "";
+ mesn;
+ mesq l("Ok. They must be playing hide and seek. Thanks again... I can't express how grateful I am.");
+ next;
+ setq HurnscaldQuests_Rossy, 3;
+ mesn;
+ mesq l("I'll now book you a room on the Inn.");
+ select
+ l("Thanks."),
+ l("Actually, please don't. I do this out of the goodness of my heart.");
+ mes "";
+ // Do not register the inn
+ if (@menu == 2) {
+ mesn;
+ mesq l("Oh... Okay, then!");
+ return;
+ }
+ // Register the inn
+ INN_REGISTER = RUSTYPICK_INN;
+ PC_IS_DEAD = false;
+ savepoint "008-2-4", 26, 27;
+ return;
+}
+
+function olanaDeliverBerries {
+ mesn;
+ mesq l("Hello there.");
+ next;
+ select
+ l("Erm, hi."),
+ l("Hi, Rossy asked me to give you this. She says it is a gift from both her and Juliet.");
+ mes "";
+ if (@menu == 1)
+ return;
+ mesn;
+ mesq l("Ohhh... How sweet... Sometimes Rossy impresses me with her kindness. Here... You are spending so much time helping us, and we give nothing back. Take this as a small reward.");
+ quest_xp(.maxLevel, 2000);
+ quest_jxp(.maxLevel, 200);
+ quest_gp(.maxLevel, 10000);
+ setq HurnscaldQuests_Rossy, 5;
+ next;
+ mesn;
+ mesq l("Could you do me a small favor, though? I know I barely know you, and you must be very busy, but...");
+ next;
+ olanaGetLetter();
+ return;
+}
+
+function olanaGetLetter {
+ mesn;
+ mesq l("Would you mind giving this letter to my little Rossy? You see, Rossy and Juliet are enrolled at Tulimshar Magic School...");
+ next;
+ mesn;
+ mesq l("Rossy is doing alchemy, and I received a letter signed by Hocus, the Grandmaster. She did not submit her exam before we travelled, and now she is running out of time...");
+ next;
+ mesn;
+ mesq l("Pretty please?");
+ next;
+ if (askyesno() == ASK_NO)
+ return;
+ mesn;
+ mesq l("Thank you again. Please, bring it to her as fast as you can.");
+ setq HurnscaldQuests_Rossy, 6;
+ return;
+}
+
+function olanaRossyGoodGirl {
+ mesn strcharinfo(0);
+ select
+ l("Rossy passed her exam.");
+ mes "";
+ mesn;
+ mesq l("That's a relief to hear! I'm so proud of her.");
+ next;
+ mesn;
+ mesq l("Could you do me a favor? Could you bring her %d %s? I am sure she will love them!", 15, getitemlink(ARedRose));
+ next;
+ select
+ l("Okay, I'll get the roses and give them to her."),
+ l("What? No way!");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("I know this won't be enough, but here is %d E to help you.", 50);
+ next;
+ mesn;
+ mesq l("After you get them, please deliver them to my brilliant daughter, Rossy.");
+ Zeny+=50;
+ setq HurnscaldQuests_Rossy, 11;
+ return;
+}
+
+function olanaRossyBadMom {
+ mesn;
+ mesq l("Did she like my present?");
+ next;
+ select
+ l("Sure she did..."),
+ l("Well, you should have known that your daughter is allergic to roses.");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mes "%%H";
+ return;
+ }
+ mesn;
+ mesq l("Oh, how stupid I am! Here, take some of my money and buy Red Tulips instead, the same amount. Keep the flowers.");
+ next;
+ mesn;
+ mesq l("Please, tell Rossy I am really sorry. My mind was on Juliet when I asked you to bring the red roses — they are her favorite.");
+ next;
+ mesn strcharinfo(0);
+ select
+ l("I will give her the tulips when I see her.");
+ mes "";
+ mesn;
+ mesq l("Thank you. And don't forget to tell her that I'm really sorry.");
+ Zeny+=450;
+ setq HurnscaldQuests_Rossy, 13;
+ return;
+}
+
+function olanaRossyHappy {
+ mesn;
+ mesq l("So?");
+ next;
+ select
+ l("Rossy was happy with your gift, and asked me to say you are the nicest mother in the world.");
+ mes "";
+ mesn;
+ mesq l("I'm so glad to hear that! But, have you seen Juliet too, by any chance?");
+ next;
+ select
+ l("Erm, no, sorry."),
+ l("I'm sure she is fine.");
+ mes "";
+ mesn;
+ mesq l("For some reason, I can't get off my mind she is in danger... Motherly instincts.");
+ next;
+ mesn;
+ mesq l("For now, I should reward you for all your effort thus far.");
+ .@item=any(Diamond, Ruby, Emerald, Sapphire, Topaz, Amethyst);
+ inventoryplace .@item, 1;
+ setq HurnscaldQuests_Rossy, 15;
+ getitem .@item, 1;
+ next;
+ mesn;
+ mesq l("But please, could you look for Juliet as well? I'm starting to get deeply worried, here.");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ .minLevel = 40;
+ .maxLevel = 80; // Differs from Juliet/Rossy
+ end;
+}
diff --git a/npc/008-2-5/_import.txt b/npc/008-2-5/_import.txt
new file mode 100644
index 00000000..74e70e1c
--- /dev/null
+++ b/npc/008-2-5/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-2-5: The Rusty Pick
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-5/_warps.txt",
+"npc/008-2-5/mapflags.txt",
diff --git a/npc/008-2-5/_warps.txt b/npc/008-2-5/_warps.txt
new file mode 100644
index 00000000..21b7f527
--- /dev/null
+++ b/npc/008-2-5/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-5: The Rusty Pick warps
+008-2-5,24,24,0 warp #008-2-5_24_24 0,0,008-2-2,52,31
diff --git a/npc/008-2-5/mapflags.txt b/npc/008-2-5/mapflags.txt
new file mode 100644
index 00000000..435dd353
--- /dev/null
+++ b/npc/008-2-5/mapflags.txt
@@ -0,0 +1 @@
+008-2-5 mapflag town
diff --git a/npc/008-2-6/_import.txt b/npc/008-2-6/_import.txt
new file mode 100644
index 00000000..38c19068
--- /dev/null
+++ b/npc/008-2-6/_import.txt
@@ -0,0 +1,6 @@
+// Map 008-2-6: Two Guys One Bed
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-6/_warps.txt",
+"npc/008-2-6/alan.txt",
+"npc/008-2-6/donald.txt",
+"npc/008-2-6/mapflags.txt",
diff --git a/npc/008-2-6/_warps.txt b/npc/008-2-6/_warps.txt
new file mode 100644
index 00000000..ed2e74a0
--- /dev/null
+++ b/npc/008-2-6/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-6: Two Guys One Bed warps
+008-2-6,27,34,0 warp #008-2-6_27_34 0,0,008-1,260,106
diff --git a/npc/008-2-6/alan.txt b/npc/008-2-6/alan.txt
new file mode 100644
index 00000000..a439c91a
--- /dev/null
+++ b/npc/008-2-6/alan.txt
@@ -0,0 +1,311 @@
+// Evol scripts.
+// Author:
+// Jesusalva
+// Micksha
+// Description:
+// Alan the bow-maker.
+// Quest states (forest bow):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - alan wants to ask jack
+// [1] 3 - jack explained problem
+// [1] 4 - alan asks to find wood
+// [1] 5 - found perfect wood
+// [1] 6 - got the bow
+// [2] fail count
+// [3] unused
+// [t] unused
+
+008-2-6,31,26,0 script Alan NPC_YOUNG_MAN_KFAHR,{
+
+ function bow_intro {
+ speech(4,
+ l("When you want to buy something then please speak to my apprentice."),
+ l("I am only doing special requests."));
+
+ selectd(
+ l("OK, thanks."),
+ rif(BaseLevel >= .min_level, l("Can you make me a really good bow?")),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything strange recently that might be connected to the robberies?")));
+
+ switch (@menu)
+ {
+ case 1: closeclientdialog(); close;
+ case 3: speech(l("No.")); close;
+ }
+
+ speech(4,
+ l("You mean like one of my legendary forest bows?"));
+
+ selectd(
+ l("Yes, that would be nice."));
+
+ speech(4,
+ l("Sorry, I am not making these anymore."));
+
+ selectd(
+ l("Oh, too bad."),
+ l("What? Why not?"));
+
+ if (@menu == 1) {
+ closeclientdialog();
+ close;
+ }
+
+ speech(4,
+ l("The problem is that I am short of material."),
+ l("My forestbows are not made of regular wood, you know."),
+ l("They are made of special living wood."),
+ l("And only the best logs of living wood are good enough for them."),
+ l("I used to get these logs from Jack, the handsome lumberjack."),
+ l("But the last time I asked him for a new delivery he said that he would never again get any for me."));
+
+ selectd(
+ l("Too bad."),
+ l("Did you ask him why?"));
+
+ if (@menu == 1) {
+ closeclientdialog();
+ close;
+ }
+
+ speech(4,
+ l("Sure I did."),
+ l("But he just told me to leave him alone."),
+ l("Maybe you could ask him what's wrong?"));
+
+ selectd(
+ l("OK, I'll ask him."),
+ l("I am sure he got his reasons."));
+
+ setq(.quest_bow, 2);
+ closeclientdialog();
+ close;
+ }
+
+ function bow_reminder {
+ if (getq(.quest_inspector) == 2)
+ {
+ speech(4,
+ l("Did you already ask Jack why he won't deliver me any more living wood?"));
+
+ selectd(
+ l("Have you seen anything strange recently that might be connected to the robberies?"));
+
+ speech(l("No."));
+ close;
+ }
+
+ npctalk3(l("Did you already ask Jack why he won't deliver me any more living wood?"));
+ end;
+ }
+
+ function bow_explain {
+ speech(4,
+ l("Did you already ask Jack why he won't deliver me any more living wood?"));
+
+ selectd(
+ l("Yes, I did. He said that the trees turned into dangerous monsters."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything strange recently that might be connected to the robberies?")));
+
+ if (@menu != 1)
+ {
+ speech(l("No."));
+ close;
+ }
+
+ speech(
+ l("Oh, that's really bad news."),
+ l("Maybe you can do his job?"),
+ l("If you kill some of these tree monsters and bring me their wood I could take a look at them."),
+ l("Maybe you will find a piece of wood that is strong enough to become one of my forest bows."));
+
+ close2;
+ setq(.quest_bow, 4);
+ end;
+ }
+
+ function bow_make {
+ speech(4,
+ l("I can make you a really nice forest bow out of this."),
+ l("I just need %s E for material and work time.",
+ format_number(.req_esp)));
+
+ selectd(
+ l("%s??? What a ripoff!", format_number(.req_esp)),
+ rif(Zeny >= .req_esp, l("Sure, here you go!")),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything strange recently that might be connected to the robberies?")));
+
+ switch (@menu)
+ {
+ case 1: speech(l("Fine, I'll just hold on to this log should you ever change your mind.")); close;
+ case 3: speech(l("No.")); close;
+ }
+
+ // XXX: maybe here we could make the player wait real-world hours for Alan to finish?
+
+ if (checkweight(.reward_item, 1) != true)
+ {
+ speech(
+ l("It seems you can't carry the bow right now."),
+ l("Go clean up your inventory and come back."));
+ close;
+ }
+
+ if (Zeny < .req_esp)
+ close; // double-check
+
+ setq(.quest_bow, 6);
+ Zeny -= .req_esp;
+ getitem(.reward_item, 1);
+ quest_xp(.maxLevel, .reward_exp);
+
+ speech(
+ l("Here you go - have fun with it."));
+ close;
+ }
+
+ function bow_check_wood {
+ speech(4,
+ l("How is the hunt going?"),
+ l("Did you bring me any wood?"));
+
+ selectd(
+ l("No, sorry."),
+ rif(countitem(.req_item) >= 1, l("Here, take a look!")),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything strange recently that might be connected to the robberies?")));
+
+ switch (@menu)
+ {
+ case 1: closeclientdialog(); close;
+ case 3: speech(l("No.")); close;
+ }
+
+ .@first = true;
+
+ do {
+ if (countitem(.req_item) < 1)
+ break;
+
+ if (.@first == false)
+ {
+ narrator(4,
+ l("You hand him another log."));
+ }
+
+ delitem(.req_item, 1);
+ .@first = false;
+
+ speech(4,
+ l("Hmmm... looks ok, but is it strong enough?"));
+
+ narrator(4,
+ l("Alan bends the log over his knee."));
+
+ .@fails=getq2(.quest_bow);
+ if (rand(.minfail, .maxfail) - .@fails <= 0)
+ {
+ narrator(4 | 8,
+ l("Alan tries as hard as he can but the log won't bend."));
+
+ speech(4,
+ l("Aaah!"),
+ l("Yes!"),
+ l("That is a really fine piece of wood you brought me."),
+ l("It will make an excellent bow!"));
+
+ setq(.quest_bow, 5);
+ setq(.quest_shield, 1);
+
+ narrator(4,
+ l("He proceeds to further scrutinize the log."));
+
+ bow_make;
+ end;
+ }
+ setq2(.quest_bow, .@fails+1);
+
+ narrator(4 | 8,
+ l("The log breaks with a loud crack."));
+
+ speech(4,
+ l("Sorry, this log was too weak for one of my forest bows."),
+ l("Now it is junk."),
+ l("Do you wish to try again?"));
+
+ selectd(
+ l("Sure, here you go."),
+ l("Hey! Stop breaking my stuff!"));
+
+ if (@menu != 1) {
+ closeclientdialog();
+ close;
+ }
+
+ } while (true);
+
+ speech(l("It seems you have no wood left."));
+ close;
+ }
+
+ function bow_done {
+ speech(4,
+ l("I hope you are satisfied with your forest bow."),
+ l("It is one of my best works."));
+
+ selectd(
+ l("I am!"),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything strange recently that might be connected to the robberies?")));
+
+ switch (@menu)
+ {
+ case 2: speech(l("No.")); close;
+ default: closeclientdialog(); close;
+ }
+ }
+
+ // OnTalk:
+ switch (getq(.quest_bow))
+ {
+ case 0:
+ case 1: bow_intro; break;
+ case 2: bow_reminder; break;
+ case 3: bow_explain; break;
+ case 4: bow_check_wood; break;
+ case 5: bow_make; break;
+ default: bow_done; break;
+ }
+
+ closeclientdialog();
+ close;
+
+OnPCLoginEvent:
+OnPCBaseLvUpEvent:
+ if (BaseLevel >= .min_level && getq(.quest_bow) < 1)
+ {
+ setq(.quest_bow, 1); // allow the player to do the quest
+ dispbottom(l("New quest available: %s (level %d+)",
+ getquestlink(.quest_bow), .min_level)); // XXX: requires new manaplus versions, maybe show a different message for old versions?
+ }
+ end;
+
+OnInit:
+ .min_level = 25; // min level to do the quest
+ .maxLevel = 50; // max level to obtain full rewards
+
+ .req_item = RawLog; // item required to make the bow
+ .req_esp = 10000; // amount of Esperin required to make the bow
+ .reward_item = ForestBow; // quest reward (item)
+ .reward_exp = 500; // quest reward (exp)
+
+ // one in X chances to get a perfect log
+ .minfail = 10;
+ .maxfail = 30;
+
+ .quest_bow = HurnscaldQuests_ForestBow;
+ .quest_shield = HurnscaldQuests_WoodenShield;
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_bow;
+ .distance = 3;
+ end;
+}
diff --git a/npc/008-2-6/donald.txt b/npc/008-2-6/donald.txt
new file mode 100644
index 00000000..5c75896e
--- /dev/null
+++ b/npc/008-2-6/donald.txt
@@ -0,0 +1,39 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Alan's Apprentice.
+
+008-2-6,29,27,0 script Donald NPC_YOUNG_MAN_APPRENTICE,{
+ if (shopcount(TrainingArrow) <= 0 && shopcount(IronArrow) <= 0) {
+ speech
+ l("Good day."),
+ l("Sorry, we are sold out for today."),
+ l("Come back later.");
+
+ } else {
+ speech
+ l("Good day."),
+ l("We got new supplies of arrows!");
+
+ next;
+
+ closeclientdialog;
+ shop .name$;
+ }
+
+ close;
+
+OnInit:
+ .distance = 4;
+ tradertype(NST_MARKET);
+
+ sellitem TrainingArrow, -1, 20000+rand2(5000);
+ sellitem IronArrow, -1, 20000+rand2(5000);
+ end;
+
+OnClock0002:
+ restoreshopitem TrainingArrow, 20000+rand2(5000);
+ restoreshopitem IronArrow, 20000+rand2(5000);
+ end;
+}
diff --git a/npc/008-2-6/mapflags.txt b/npc/008-2-6/mapflags.txt
new file mode 100644
index 00000000..c07673a4
--- /dev/null
+++ b/npc/008-2-6/mapflags.txt
@@ -0,0 +1 @@
+008-2-6 mapflag town
diff --git a/npc/008-2-7/_import.txt b/npc/008-2-7/_import.txt
new file mode 100644
index 00000000..d3391d83
--- /dev/null
+++ b/npc/008-2-7/_import.txt
@@ -0,0 +1,8 @@
+// Map 008-2-7: Hurnscald Apothecary
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-7/_savepoints.txt",
+"npc/008-2-7/_warps.txt",
+"npc/008-2-7/mapflags.txt",
+"npc/008-2-7/shop.txt",
+"npc/008-2-7/simon.txt",
+"npc/008-2-7/wyara.txt",
diff --git a/npc/008-2-7/_savepoints.txt b/npc/008-2-7/_savepoints.txt
new file mode 100644
index 00000000..ab8ddbb4
--- /dev/null
+++ b/npc/008-2-7/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-7: Hurnscald Apothecary saves
+008-2-7,25,27,0 script #save_008-2-7_25_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-7/_warps.txt b/npc/008-2-7/_warps.txt
new file mode 100644
index 00000000..ffd0f758
--- /dev/null
+++ b/npc/008-2-7/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-7: Hurnscald Apothecary warps
+008-2-7,36,30,0 warp #008-2-7_36_30 0,0,008-1,272,103
diff --git a/npc/008-2-7/mapflags.txt b/npc/008-2-7/mapflags.txt
new file mode 100644
index 00000000..caeb89e9
--- /dev/null
+++ b/npc/008-2-7/mapflags.txt
@@ -0,0 +1 @@
+008-2-7 mapflag town
diff --git a/npc/008-2-7/shop.txt b/npc/008-2-7/shop.txt
new file mode 100644
index 00000000..3771978a
--- /dev/null
+++ b/npc/008-2-7/shop.txt
@@ -0,0 +1,35 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Micksha
+// Reid
+// toams
+// Description:
+// Simons Potion Shop.
+
+008-2-7,30,26,0 trader #Invisible008-2-7 NPC_HIDDEN,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem SmallHealing, -1, 10;
+ sellitem MediumHealing, -1, 5;
+ sellitem SmallMana, -1, 10;
+ sellitem MediumMana, -1, 5;
+ sellitem ConcPotion, -1, 3;
+ sellitem IronPotion, -1, 3;
+
+ .distance = 4;
+ end;
+
+OnClock0000:
+OnClock0800:
+OnClock1600:
+ restoreshopitem SmallHealing, 10;
+ restoreshopitem MediumHealing, 5;
+ restoreshopitem SmallMana, 10;
+ restoreshopitem MediumMana, 5;
+ restoreshopitem ConcPotion, 3;
+ restoreshopitem IronPotion, 3;
+ end;
+}
diff --git a/npc/008-2-7/simon.txt b/npc/008-2-7/simon.txt
new file mode 100644
index 00000000..8562199a
--- /dev/null
+++ b/npc/008-2-7/simon.txt
@@ -0,0 +1,38 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Simon, Wyaras Apprentice.
+// THIS IS A PLACEHOLDER!
+
+008-2-7,30,26,0 script Simon NPC_SIMON,{
+ speech
+ l("Hi, I am Simon."),
+ l("I am Wyaras apprentice, helping her with selling her potions."),
+ l("I would prefer becoming a real Sorcerer one time. *sighs*");
+
+ switch (select(l("Potions? That sounds useful. What do you have?"),
+ l("Thats your problem, really."),
+ l("Becoming a Sorcerer? I want that too!")))
+ {
+ case 1:
+ closeclientdialog;
+ shop "#Invisible008-2-7";
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("Leave me alone.");
+ close;
+ case 3:
+ speech S_FIRST_BLANK_LINE,
+ l("It needs so much training, but Wyara only leaves me here, standing and selling something instead of teaching me.");
+ close;
+ }
+
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-7/wyara.txt b/npc/008-2-7/wyara.txt
new file mode 100644
index 00000000..7bac6efc
--- /dev/null
+++ b/npc/008-2-7/wyara.txt
@@ -0,0 +1,29 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Wyara the witch.
+// TODO: Buy or make plushroom potions
+
+008-2-7,27,28,0 script Wyara NPC_DARK_DRUID,{
+ speech
+ l("What? Is there someone?"),
+ l("Please, leave me alone. I have to pixel- erm, brew potions."),
+ l("I will sell some when you return a bit later."),
+ l("Unless you are interested in a status reset?");
+ next;
+ select
+ l("I'm fine, thanks."),
+ l("I actually could use a status reset!");
+ mes "";
+ switch (@menu) {
+ case 2:
+ ConfirmStatusReset();
+ break;
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-2-8/_import.txt b/npc/008-2-8/_import.txt
new file mode 100644
index 00000000..8bb44bb1
--- /dev/null
+++ b/npc/008-2-8/_import.txt
@@ -0,0 +1,6 @@
+// Map 008-2-8: Hurnscald Forge
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-8/_warps.txt",
+"npc/008-2-8/macgowan.txt",
+"npc/008-2-8/mapflags.txt",
+"npc/008-2-8/nicholas.txt",
diff --git a/npc/008-2-8/_warps.txt b/npc/008-2-8/_warps.txt
new file mode 100644
index 00000000..ca801b84
--- /dev/null
+++ b/npc/008-2-8/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-8: Hurnscald Forge warps
+008-2-8,37,39,0 warp #008-2-8_37_39 1,0,008-1,292,119
+008-2-8,26,29,0 warp #008-2-8_26_29 0,0,008-1,287,114
diff --git a/npc/008-2-8/macgowan.txt b/npc/008-2-8/macgowan.txt
new file mode 100644
index 00000000..efeee33e
--- /dev/null
+++ b/npc/008-2-8/macgowan.txt
@@ -0,0 +1,24 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// The Smith's apprentice.
+// THIS IS A PLACEHOLDER!
+
+008-2-8,38,29,0 script Macgowan NPC_YOUNG_MAN_APPRENTICE,{
+ npctalk3(l("Hello, I am Macgowan, apprentice to Nicholas."));
+ end;
+
+OnInit:
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-2-8/mapflags.txt b/npc/008-2-8/mapflags.txt
new file mode 100644
index 00000000..2bdbedb9
--- /dev/null
+++ b/npc/008-2-8/mapflags.txt
@@ -0,0 +1 @@
+008-2-8 mapflag town
diff --git a/npc/008-2-8/nicholas.txt b/npc/008-2-8/nicholas.txt
new file mode 100644
index 00000000..7b62090d
--- /dev/null
+++ b/npc/008-2-8/nicholas.txt
@@ -0,0 +1,28 @@
+// Evol scripts.
+// Author:
+// gumi, Micksha
+// Description:
+// Nicholas the Smith.
+
+008-2-8,40,27,0 script Nicholas NPC_NICHOLAS,{
+ speech(
+ l("Hello, there!"),
+ l("I'm an expert blacksmith."),
+ l("If you get me some Coal and Iron Ingots, I could make you a very valuable shield or helmet."));
+
+ // TODO: setzer quest
+ close;
+
+OnInit:
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-2-9/_import.txt b/npc/008-2-9/_import.txt
new file mode 100644
index 00000000..aade14bd
--- /dev/null
+++ b/npc/008-2-9/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-2-9: Jack's Abode
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2-9/_savepoints.txt",
+"npc/008-2-9/_warps.txt",
+"npc/008-2-9/mapflags.txt",
diff --git a/npc/008-2-9/_savepoints.txt b/npc/008-2-9/_savepoints.txt
new file mode 100644
index 00000000..b606d73c
--- /dev/null
+++ b/npc/008-2-9/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-9: Jack's Abode saves
+008-2-9,26,31,0 script #save_008-2-9_26_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/008-2-9/_warps.txt b/npc/008-2-9/_warps.txt
new file mode 100644
index 00000000..71ae1413
--- /dev/null
+++ b/npc/008-2-9/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2-9: Jack's Abode warps
+008-2-9,30,35,0 warp #008-2-9_30_35 0,0,008-1,243,116
diff --git a/npc/008-2-9/mapflags.txt b/npc/008-2-9/mapflags.txt
new file mode 100644
index 00000000..e637ae03
--- /dev/null
+++ b/npc/008-2-9/mapflags.txt
@@ -0,0 +1 @@
+008-2-9 mapflag town
diff --git a/npc/008-3-0/_import.txt b/npc/008-3-0/_import.txt
new file mode 100644
index 00000000..4ff9254d
--- /dev/null
+++ b/npc/008-3-0/_import.txt
@@ -0,0 +1,6 @@
+// Map 008-3-0: Rossy Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-0/_mobs.txt",
+"npc/008-3-0/_warps.txt",
+"npc/008-3-0/clauquer.txt",
+"npc/008-3-0/juliet.txt",
diff --git a/npc/008-3-0/_mobs.txt b/npc/008-3-0/_mobs.txt
new file mode 100644
index 00000000..06015caf
--- /dev/null
+++ b/npc/008-3-0/_mobs.txt
@@ -0,0 +1,83 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-0: Rossy Cave mobs
+008-3-0,30,113,7,14 monster Cave Maggot 1027,5,500,2000
+008-3-0,102,116,14,8 monster Cave Maggot 1027,5,500,2000
+008-3-0,79,144,10,6 monster Cave Maggot 1027,7,500,2000
+008-3-0,158,87,10,12 monster Cave Maggot 1027,7,500,2000
+008-3-0,34,28,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,160,124,5,3 monster Ratto 1005,4,35000,15000
+008-3-0,155,163,1,7 monster Ratto 1005,4,35000,15000
+008-3-0,128,146,5,3 monster Ratto 1005,4,35000,15000
+008-3-0,120,61,5,3 monster Ratto 1005,4,35000,15000
+008-3-0,138,64,10,7 monster Crafty 1018,10,1000,120000
+008-3-0,129,102,11,6 monster Crafty 1018,6,1000,120000
+008-3-0,67,114,10,2 monster Spider 1044,3,4000,8000
+008-3-0,109,145,4,10 monster Spider 1044,5,4000,8000
+008-3-0,68,84,3,7 monster Spider 1044,4,4000,8000
+008-3-0,80,169,0,0 monster Diamond Vein 1045,1,600000,60000
+008-3-0,118,96,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,131,93,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-0,119,101,0,0 monster Gold Veinbloc 1070,1,600000,60000
+008-3-0,113,60,23,8 monster Cave Maggot 1027,7,500,2000
+008-3-0,199,68,8,9 monster Crafty 1018,5,1000,60000
+008-3-0,160,47,17,5 monster Crafty 1018,5,1000,120000
+008-3-0,119,200,20,4 monster Spider 1044,5,4000,8000
+008-3-0,34,193,11,9 monster Spider 1044,5,4000,8000
+008-3-0,26,115,5,17 monster Spider 1044,5,4000,8000
+008-3-0,82,60,21,7 monster Cave Maggot 1027,5,500,2000
+008-3-0,38,193,16,4 monster Cave Maggot 1027,5,500,2000
+008-3-0,114,199,12,3 monster Ratto 1005,4,35000,15000
+008-3-0,106,30,10,7 monster Crafty 1018,5,1000,120000
+008-3-0,78,128,11,21 monster Ratto 1005,4,35000,15000
+008-3-0,117,141,35,11 monster Crafty 1018,10,1000,120000
+008-3-0,117,101,18,11 monster Ratto 1005,7,35000,15000
+008-3-0,130,88,0,0 monster Ruby Vein 1051,1,600000,60000
+008-3-0,122,94,0,0 monster Ruby Vein 1051,1,600000,60000
+008-3-0,31,181,0,0 monster Sapphire Vein 1053,1,600000,60000
+008-3-0,31,198,0,0 monster Sapphire Vein 1053,1,600000,60000
+008-3-0,135,127,0,0 monster Topaz Vein 1054,1,600000,60000
+008-3-0,120,125,0,0 monster Topaz Vein 1054,1,600000,60000
+008-3-0,31,112,0,0 monster Amethyst Vein 1055,1,600000,60000
+008-3-0,24,123,0,0 monster Amethyst Vein 1055,1,600000,60000
+008-3-0,193,123,0,0 monster Emerald Vein 1052,1,600000,60000
+008-3-0,204,116,0,0 monster Emerald Vein 1052,1,600000,60000
+008-3-0,89,168,0,0 monster Diamond Vein 1045,1,600000,60000
+008-3-0,132,192,0,0 monster Sapphire Vein 1053,1,600000,60000
+008-3-0,39,174,0,0 monster Amethyst Vein 1055,1,600000,60000
+008-3-0,44,174,0,0 monster Topaz Vein 1054,1,600000,60000
+008-3-0,118,196,0,0 monster Emerald Vein 1052,1,600000,60000
+008-3-0,65,105,0,0 monster Diamond Vein 1045,1,600000,60000
+008-3-0,143,139,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,156,121,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,155,166,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,125,162,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,107,141,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,77,148,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,62,119,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-0,162,95,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-0,157,66,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-0,112,60,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-0,66,54,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-0,63,91,0,0 monster Gold Veinbloc 1070,1,600000,60000
+008-3-0,76,127,0,0 monster Gold Veinbloc 1070,1,600000,60000
+008-3-0,111,148,0,0 monster Gold Veinbloc 1070,1,600000,60000
+008-3-0,101,27,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,165,28,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,199,67,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,199,109,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,197,194,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,133,199,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,34,194,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,26,111,3,4 monster Poison Skull 1100,1,35000,60000
+008-3-0,88,48,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-0,100,49,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-0,130,44,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-0,67,47,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-0,124,94,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-0,158,60,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-0,56,53,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-0,55,98,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-0,62,103,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-0,69,125,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-0,62,153,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-0,96,145,0,0 monster Iron Vein 1047,1,600000,60000
diff --git a/npc/008-3-0/_warps.txt b/npc/008-3-0/_warps.txt
new file mode 100644
index 00000000..74a3623b
--- /dev/null
+++ b/npc/008-3-0/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-0: Rossy Cave warps
+008-3-0,130,113,0 warp #008-3-0_130_113 1,0,008-1,49,158
diff --git a/npc/008-3-0/clauquer.txt b/npc/008-3-0/clauquer.txt
new file mode 100644
index 00000000..845596d7
--- /dev/null
+++ b/npc/008-3-0/clauquer.txt
@@ -0,0 +1,138 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Shaddy man
+
+008-3-0,129,94,0 script Clauquer NPC_CAUL,{
+ function clauquerPrologue;
+
+ // HurnscaldQuests_Rossy
+ // (MAIN QUEST, CAVE CONTROL, INSTANCE CONTROL)
+ .@q=getq(HurnscaldQuests_Rossy);
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ .@inst=getq3(HurnscaldQuests_Rossy);
+
+ // Instance zero is reserved for La Marine
+ if (instance_id() <= 0 || .@q != 16) {
+ mesn;
+ mesq l("Huh? Why are you here? Get out.");
+ close;
+ }
+ mesn;
+ mesq l("Hello stranger, are you lost?");
+ if (.@q < 16)
+ close;
+ if (!.@q2) {
+ clauquerPrologue();
+ close;
+ }
+ next;
+ .@caves=bitmask_count(.@q2)-1;
+ mesn;
+ if (.@q2 > ROSSY_BOSSCAVE || .@q > 16)
+ .@msg$=l("Good job rescuing the little girl!");
+ else if (.@q2 == ROSSY_READY)
+ .@msg$=l("I am amazed... You eliminated all the 9 energy sources. Now is the difficult part. To save the girl, you need to eliminate the last and most powerful barrier. Good Luck!");
+ else if (.@q2 <= ROSSY_PROLOGUE)
+ .@msg$=l("Well... You didn't eliminate any of the barriers, so that means there are still 9 caves and the tenth one, the strongest...");
+ else
+ .@msg$=l("You are doing good... If I am right, you already eliminated %d of the 9 energy sources of the barrier that protects the cave in which the girl is being kept captive.", .@caves);
+
+ mesq .@msg$;
+ if (.@q == 16 && .@caves < ROSSY_BOSSCAVE) {
+ next;
+ select
+ l("Thanks."),
+ l("But please, I really need your help!");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Well, I already told you what I knew, but repeating never hurts, I guess. So, to nullify the barrier.");
+ next;
+ clauquerPrologue();
+ }
+ }
+ close;
+
+function clauquerPrologue {
+ // HurnscaldQuests_Rossy
+ // (MAIN QUEST, CAVE CONTROL, INSTANCE CONTROL)
+ .@q=getq(HurnscaldQuests_Rossy);
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ .@inst=getq3(HurnscaldQuests_Rossy);
+
+ // Prologue
+ if (!(.@q2 & ROSSY_PROLOGUE)) {
+ next;
+ mesn;
+ mesq l("Don't answer— I know you are looking for someone... A little girl, is that right?");
+ next;
+ select
+ l("I must admit you're right, but how come you..."),
+ l("I'm not lost and I don't need help, bye.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("How do I know you're looking for her? Well, because I am a very good observer. I know you were helping her family. Besides, I saw the little girl. I also heard her. She screamed, and probably still screams like hell. Moreover, I don't think you would enter these caves just for fun!");
+ next;
+ select l("Of course not.");
+ mes "";
+ mesn;
+ mesq l("I can see that you really want to save the little girl. She is trapped in a place inside one of these caves, protected by a magic barrier created by a fey spirit. To save her, you have to annulate the energy sources of this barrier. They are located in 10 different spots, each one in a different cave.");
+ next;
+ select l("But how can I annulate this barrier?");
+ mes "";
+ }
+ // Common
+ mesn;
+ mesq l("It is simple, you just have to place a %s on the exact center of the energy source. Once you do this, its entire power will transmute into some terrible earth monsters. If you defeat them, this source of energy will be close to nothing and the barrier will be weaker.", getitemlink(PileOfAsh));
+ next;
+ mesn;
+ mesq l("If my observations are correct, the girl is trapped in a cave protected by a barrier fed by 9 different power sources. And inside this cave there is another barrier, fed by a single, but very strong, power source. The girl is inside that cave, protected by that strong barrier.");
+ next;
+ mesn;
+ mesq l("Be prepared before you enter one of these caves, because once you put the root in the power source, you won't be able to get out. Also, remember that you can't stay in these caves for a long time, because of the foul air.");
+ mesc l("If you take more than %d minutes between a boss fight and other, you'll faint and the quest will reset!!", 20), 1;
+ next;
+ // Prologue (FIXME)
+ if (!(.@q2 & ROSSY_PROLOGUE)) {
+ mesn;
+ mesq l("Now I should tell you more about how that little girl got into that cave and warn you about what you are going to face there...");
+ next;
+ select l("Please go on.");
+ mes "";
+ mesn;
+ mesq l("I advise you to be mentally prepared for this rescue operation. You'll be fighting a selection of monsters in these caves with mixed elements.");
+ next;
+ mesn;
+ mesq l("Also, the old tales of Hurnscald say that a Golem inhabits these caves and smashes anyone who enters here ill prepared; but it can be tamed and made into subservience by a sacrifice. And I saw the girl heading to said room...");
+ next;
+ mesn;
+ mesq l("However, hope is not yet lost. If you were to, say, defeat the Golem before it is fully awakened, the girl would be saved... Time, however, is not on your favor and is of essence. And I am no fighter, so I cannot help you.");
+ next;
+ }
+ mesn;
+ mesq l("Oh, and if you really plan to rescue the girl, I advise you to use potions for every single battle. I'm thinking of Concentration and Iron Potions. You might want to take some food with you too. I would personally take some water, I'm always thirsty. Don't be afraid to bring too much with you, these battles take time to end.");
+ next;
+ mesn;
+ mesq l("I think you're now ready to explore these caves and fight. Good luck rescuing the girl!");
+
+ // Renew the timer the first time you see the prologue
+ if (!.@q2) {
+ instance_set_timeout(ROSSY_INSTIME, ROSSY_INSTIME, .@inst);
+ addtimer2(300000, "#RossyQuest::OnTick1");
+ deltimer("#RossyQuest::OnTick2");
+ deltimer("#RossyQuest::OnTick3");
+ deltimer("#RossyQuest::OnTick4");
+ deltimer("#RossyQuest::OnTick5");
+ }
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_PROLOGUE;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-3-0/juliet.txt b/npc/008-3-0/juliet.txt
new file mode 100644
index 00000000..e0d256be
--- /dev/null
+++ b/npc/008-3-0/juliet.txt
@@ -0,0 +1,656 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Core for rescuing Juliet.
+// Named as "Juliet" so `pluma npc/*/juliet.txt` resolves to something tangible.
+008-3-0 mapflag nosave 008-1-1,49,158
+
+008-3-0,92,89,0 script Summoning Altar#Rossy NPC_NO_SPRITE,{
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ // Not ready
+ if (.@q2 < ROSSY_READY) {
+ mesn;
+ mesq l("Better not touch this.");
+ close;
+ }
+ // Complete
+ if (.@q2 & ROSSY_BOSSCAVE) {
+ dispbottom l("You find someone hiding behind the altar.");
+ enablenpc instance_npcname("Juliet");
+ disablenpc instance_npcname("Summoning Altar#Rossy");
+ end;
+ }
+ // Battle
+ mesc l("This is the boss room! Be prepared for the worst!!"), 1;
+ callfunc("RossyCave", ROSSY_BOSSCAVE);
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+
+// Time to configure the map
+OnInstanceInit:
+ .@m$=instance_mapname("008-3-0");
+ // Rebuild spawns
+ // WARNING: Originals were generated automatically!
+ // print('\tareamonster(.@m$, %d, %d, %d, %d, strmobinfo(1, %s), %s, %d);' % (obj.x, obj.y, obj.x+obj.w, obj.y+obj.h, obj.name.replace(' ', ''), obj.name.replace(' ', ''), obj.max_beings))
+ areamonster(.@m$, 30, 113, 37, 127, strmobinfo(1, CaveMaggot), CaveMaggot, 5);
+ areamonster(.@m$, 102, 116, 116, 124, strmobinfo(1, CaveMaggot), CaveMaggot, 5);
+ areamonster(.@m$, 79, 144, 89, 150, strmobinfo(1, CaveMaggot), CaveMaggot, 7);
+ areamonster(.@m$, 158, 87, 168, 99, strmobinfo(1, CaveMaggot), CaveMaggot, 7);
+ areamonster(.@m$, 34, 28, 37, 32, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 160, 124, 165, 127, strmobinfo(1, Ratto), Ratto, 4);
+ areamonster(.@m$, 155, 163, 156, 170, strmobinfo(1, Ratto), Ratto, 4);
+ areamonster(.@m$, 128, 146, 133, 149, strmobinfo(1, Ratto), Ratto, 4);
+ areamonster(.@m$, 120, 61, 125, 64, strmobinfo(1, Ratto), Ratto, 4);
+ areamonster(.@m$, 138, 64, 148, 71, strmobinfo(1, Crafty), Crafty, 10);
+ areamonster(.@m$, 129, 102, 140, 108, strmobinfo(1, Crafty), Crafty, 6);
+ areamonster(.@m$, 67, 114, 77, 116, strmobinfo(1, Spider), Spider, 3);
+ areamonster(.@m$, 109, 145, 113, 155, strmobinfo(1, Spider), Spider, 5);
+ areamonster(.@m$, 68, 84, 71, 91, strmobinfo(1, Spider), Spider, 4);
+ areamonster(.@m$, 80, 169, 80, 169, strmobinfo(1, DiamondVein), DiamondVein, 1);
+ areamonster(.@m$, 118, 96, 118, 96, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 131, 93, 131, 93, strmobinfo(1, CoalVeinbloc), CoalVeinbloc, 1);
+ areamonster(.@m$, 119, 101, 119, 101, strmobinfo(1, GoldVeinbloc), GoldVeinbloc, 1);
+ areamonster(.@m$, 113, 60, 136, 68, strmobinfo(1, CaveMaggot), CaveMaggot, 7);
+ areamonster(.@m$, 199, 68, 207, 77, strmobinfo(1, Crafty), Crafty, 5);
+ areamonster(.@m$, 160, 47, 177, 52, strmobinfo(1, Crafty), Crafty, 5);
+ areamonster(.@m$, 119, 200, 139, 204, strmobinfo(1, Spider), Spider, 5);
+ areamonster(.@m$, 34, 193, 45, 202, strmobinfo(1, Spider), Spider, 5);
+ areamonster(.@m$, 26, 115, 31, 132, strmobinfo(1, Spider), Spider, 5);
+ areamonster(.@m$, 82, 60, 103, 67, strmobinfo(1, CaveMaggot), CaveMaggot, 5);
+ areamonster(.@m$, 38, 193, 54, 197, strmobinfo(1, CaveMaggot), CaveMaggot, 5);
+ areamonster(.@m$, 114, 199, 126, 202, strmobinfo(1, Ratto), Ratto, 4);
+ areamonster(.@m$, 106, 30, 116, 37, strmobinfo(1, Crafty), Crafty, 5);
+ areamonster(.@m$, 78, 128, 89, 149, strmobinfo(1, Ratto), Ratto, 4);
+ areamonster(.@m$, 117, 141, 152, 152, strmobinfo(1, Crafty), Crafty, 10);
+ areamonster(.@m$, 117, 101, 135, 112, strmobinfo(1, Ratto), Ratto, 7);
+ areamonster(.@m$, 130, 88, 130, 88, strmobinfo(1, RubyVein), RubyVein, 1);
+ areamonster(.@m$, 122, 94, 122, 94, strmobinfo(1, RubyVein), RubyVein, 1);
+ areamonster(.@m$, 31, 181, 31, 181, strmobinfo(1, SapphireVein), SapphireVein, 1);
+ areamonster(.@m$, 31, 198, 31, 198, strmobinfo(1, SapphireVein), SapphireVein, 1);
+ areamonster(.@m$, 135, 127, 135, 127, strmobinfo(1, TopazVein), TopazVein, 1);
+ areamonster(.@m$, 120, 125, 120, 125, strmobinfo(1, TopazVein), TopazVein, 1);
+ areamonster(.@m$, 31, 112, 31, 112, strmobinfo(1, AmethystVein), AmethystVein, 1);
+ areamonster(.@m$, 24, 123, 24, 123, strmobinfo(1, AmethystVein), AmethystVein, 1);
+ areamonster(.@m$, 193, 123, 193, 123, strmobinfo(1, EmeraldVein), EmeraldVein, 1);
+ areamonster(.@m$, 204, 116, 204, 116, strmobinfo(1, EmeraldVein), EmeraldVein, 1);
+ areamonster(.@m$, 89, 168, 89, 168, strmobinfo(1, DiamondVein), DiamondVein, 1);
+ areamonster(.@m$, 132, 192, 132, 192, strmobinfo(1, SapphireVein), SapphireVein, 1);
+ areamonster(.@m$, 39, 174, 39, 174, strmobinfo(1, AmethystVein), AmethystVein, 1);
+ areamonster(.@m$, 44, 174, 44, 174, strmobinfo(1, TopazVein), TopazVein, 1);
+ areamonster(.@m$, 118, 196, 118, 196, strmobinfo(1, EmeraldVein), EmeraldVein, 1);
+ areamonster(.@m$, 65, 105, 65, 105, strmobinfo(1, DiamondVein), DiamondVein, 1);
+ areamonster(.@m$, 143, 139, 143, 139, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 156, 121, 156, 121, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 155, 166, 155, 166, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 125, 162, 125, 162, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 107, 141, 107, 141, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 77, 148, 77, 148, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 62, 119, 62, 119, strmobinfo(1, GemVeinbloc), GemVeinbloc, 1);
+ areamonster(.@m$, 162, 95, 162, 95, strmobinfo(1, CoalVeinbloc), CoalVeinbloc, 1);
+ areamonster(.@m$, 157, 66, 157, 66, strmobinfo(1, CoalVeinbloc), CoalVeinbloc, 1);
+ areamonster(.@m$, 112, 60, 112, 60, strmobinfo(1, CoalVeinbloc), CoalVeinbloc, 1);
+ areamonster(.@m$, 66, 54, 66, 54, strmobinfo(1, CoalVeinbloc), CoalVeinbloc, 1);
+ areamonster(.@m$, 63, 91, 63, 91, strmobinfo(1, GoldVeinbloc), GoldVeinbloc, 1);
+ areamonster(.@m$, 76, 127, 76, 127, strmobinfo(1, GoldVeinbloc), GoldVeinbloc, 1);
+ areamonster(.@m$, 111, 148, 111, 148, strmobinfo(1, GoldVeinbloc), GoldVeinbloc, 1);
+ /*
+ areamonster(.@m$, 101, 27, 104, 31, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 165, 28, 168, 32, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 199, 67, 202, 71, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 199, 109, 202, 113, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 197, 194, 200, 198, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 133, 199, 136, 203, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 34, 194, 37, 198, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ areamonster(.@m$, 26, 111, 29, 115, strmobinfo(1, PoisonSkull), PoisonSkull, 1);
+ */
+ areamonster(.@m$, 88, 48, 88, 48, strmobinfo(1, CoalVein), CoalVein, 1);
+ areamonster(.@m$, 100, 49, 100, 49, strmobinfo(1, CoalVein), CoalVein, 1);
+ areamonster(.@m$, 130, 44, 130, 44, strmobinfo(1, CoalVein), CoalVein, 1);
+ areamonster(.@m$, 67, 47, 67, 47, strmobinfo(1, CoalVein), CoalVein, 1);
+ areamonster(.@m$, 124, 94, 124, 94, strmobinfo(1, CoalVein), CoalVein, 1);
+ areamonster(.@m$, 158, 60, 158, 60, strmobinfo(1, CoalVein), CoalVein, 1);
+ areamonster(.@m$, 56, 53, 56, 53, strmobinfo(1, IronVein), IronVein, 1);
+ areamonster(.@m$, 55, 98, 55, 98, strmobinfo(1, IronVein), IronVein, 1);
+ areamonster(.@m$, 62, 103, 62, 103, strmobinfo(1, IronVein), IronVein, 1);
+ areamonster(.@m$, 69, 125, 69, 125, strmobinfo(1, IronVein), IronVein, 1);
+ areamonster(.@m$, 62, 153, 62, 153, strmobinfo(1, IronVein), IronVein, 1);
+ areamonster(.@m$, 96, 145, 96, 145, strmobinfo(1, IronVein), IronVein, 1);
+
+ // Yay yay yay
+ end;
+}
+
+/////////////////////////////////////////////////////////
+// Main script controller for Rossy Quest
+- script #RossyQuest NPC_HIDDEN,{
+ end;
+
+OnStage2:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage2")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE1;
+ goto OnBeat;
+
+OnStage4:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage4")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE2;
+ goto OnBeat;
+
+OnStage8:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage8")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE3;
+ goto OnBeat;
+
+OnStage16:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage16")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE4;
+ goto OnBeat;
+
+OnStage32:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage32")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE5;
+ goto OnBeat;
+
+OnStage64:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage64")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE6;
+ goto OnBeat;
+
+OnStage128:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage128")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE7;
+ goto OnBeat;
+
+OnStage256:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage256")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE8;
+ goto OnBeat;
+
+OnStage512:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage512")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_CAVE9;
+ goto OnBeat;
+
+OnStage1024:
+ if (!playerattached()) end; // ERROR
+ if (!@rossylock) end; // Invalid
+ if (mobcount(getmap(), "#RossyQuest::OnStage1024")) end; // Still working
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ setq2 HurnscaldQuests_Rossy, .@q2 | ROSSY_BOSSCAVE;
+ goto OnBeat;
+
+OnBeat:
+ @rossylock = false;
+ dispbottom l("*** Cave Cleared ***");
+ delcells "Rossy"+getcharid(0)+"Wall";
+ .@inst = getq3(HurnscaldQuests_Rossy);
+ instance_set_timeout(ROSSY_INSTIME, ROSSY_INSTIME, .@inst);
+ if (.@q2 < ROSSY_BOSSCAVE)
+ addtimer2(300000, "#RossyQuest::OnTick1");
+ else
+ deltimer("#RossyQuest::OnTick1");
+ deltimer("#RossyQuest::OnTick2");
+ deltimer("#RossyQuest::OnTick3");
+ deltimer("#RossyQuest::OnTick4");
+ deltimer("#RossyQuest::OnTick5");
+ end;
+
+/* ****************************************** */
+OnTick1:
+ dispbottom l("Time remaining: %d minutes", 15);
+ addtimer2(300000, "#RossyQuest::OnTick2");
+ end;
+
+OnTick2:
+ dispbottom l("Time remaining: %d minutes", 10);
+ addtimer2(300000, "#RossyQuest::OnTick3");
+ end;
+
+OnTick3:
+ dispbottom l("Time remaining: %d minutes", 5);
+ addtimer2(240000, "#RossyQuest::OnTick4");
+ end;
+
+OnTick4:
+ dispbottom l("Time remaining: 1 minute");
+ addtimer2(45000, "#RossyQuest::OnTick5");
+ end;
+
+OnTick5:
+ dispbottom l("Time remaining: %d seconds!", 15);
+ end;
+
+}
+
+/////////////////////////////////////////////////////////
+// RossyCave(Cave ID)
+function script RossyCave {
+ // Fight ongoing - cannot trigger
+ if (@rossylock)
+ return false;
+
+ // Check quest consistency
+ // HurnscaldQuests_Rossy
+ // (MAIN QUEST, CAVE CONTROL, INSTANCE CONTROL)
+ .@q=getq(HurnscaldQuests_Rossy);
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ .@inst=getq3(HurnscaldQuests_Rossy);
+
+ if (instance_id() != .@inst)
+ return false;
+ if (.@q != 16)
+ return false;
+ if (!.@q2) {
+ dispbottom l("This looks DANGEROUS! Maybe someone around here can tell me what I'm supposed to do.");
+ return false;
+ }
+ if (.@q2 & .caveid)
+ return false;
+
+ // ---------------
+ // Main node setup
+ .@c=getarg(0);
+ .@m$=getmap();
+ .@n$="#RossyQuest::OnStage"+.@c;
+
+ // Obtain and Write Configuration
+ switch (.@c) {
+ case ROSSY_CAVE1:
+ .@boss=PoisonSkull;
+ .@mobc=rand2(3,5);
+ .@x1=85;.@y1=21;.@x2=108;.@y2=39;
+ .@x3=109;.@y3=33; .@x4=109; .@y4=36;
+ break;
+ case ROSSY_CAVE2:
+ .@boss=Troll;
+ .@mobc=rand2(3,5);
+ .@x1=191;.@y1=103;.@x2=205;.@y2=122;
+ .@x3=201;.@y3=123; .@x4=201; .@y4=123;
+ break;
+ case ROSSY_CAVE3:
+ .@boss=FireWisp;
+ .@mobc=rand2(2,4);
+ .@x1=26;.@y1=23;.@x2=43;.@y2=36;
+ .@x3=38;.@y3=37; .@x4=38; .@y4=37;
+ break;
+ case ROSSY_CAVE4:
+ .@boss=WaterWisp;
+ .@mobc=rand2(6,12);
+ .@x1=180;.@y1=176;.@x2=206;.@y2=207;
+ .@x3=179;.@y3=200; .@x4=179; .@y4=200;
+ break;
+ case ROSSY_CAVE5:
+ .@boss=Serqet;
+ .@mobc=rand2(6,8);
+ .@x1=98;.@y1=188;.@x2=141;.@y2=207;
+ .@x3=97;.@y3=190; .@x4=97; .@y4=197;
+ break;
+ case ROSSY_CAVE6:
+ .@boss=SnakeGhost;
+ .@mobc=rand2(5,7);
+ .@x1=19;.@y1=98;.@x2=36;.@y2=136;
+ .@x3=37;.@y3=125; .@x4=37; .@y4=125;
+ break;
+ case ROSSY_CAVE7:
+ .@boss=ScorpionGhost;
+ .@mobc=rand2(5,7);
+ .@x1=22;.@y1=181;.@x2=50;.@y2=205;
+ .@x3=51;.@y3=192; .@x4=51; .@y4=197;
+ break;
+ case ROSSY_CAVE8:
+ .@boss=JackO;
+ .@mobc=rand2(3,5);
+ .@x1=158;.@y1=20;.@x2=176;.@y2=35;
+ .@x3=175;.@y3=36; .@x4=177; .@y4=36;
+ break;
+ case ROSSY_CAVE9:
+ .@boss=GreenSlimeProgenitor;
+ .@mobc=rand2(5,7);
+ .@x1=187;.@y1=58;.@x2=208;.@y2=85;
+ .@x3=186;.@y3=82; .@x4=186; .@y4=85;
+ break;
+ case ROSSY_BOSSCAVE:
+ .@boss=Golem;
+ .@mobc=rand2(3,5);
+ .@x1=84;.@y1=85;.@x2=101;.@y2=101;
+ .@x3=92;.@y3=102; .@x4=93; .@y4=102;
+ break;
+ default:
+ consolemes(CONSOLEMES_ERROR, "INVALID ROSSY CAVE ID - "+.@c+" - SCRIPT ABORTED");
+ return false;
+ }
+
+ // This is cast from a dialog so prompt comes before any advanced calculation
+ mesc l("Drop a %s here to summon monsters.", getitemlink(PileOfAsh));
+ if (.@c == ROSSY_BOSSCAVE)
+ mesc l("This is the master's room seal, be careful!"), 1;
+ else
+ mesc l("Weaken all nine seals to be able to undo the final one.");
+ select
+ rif(countitem(PileOfAsh), l("Place pile of ashes")),
+ l("Run away in fear");
+ mes "";
+ closeclientdialog;
+ if (@menu == 2)
+ return false;
+
+ // Delete the item and lock for the quest
+ delitem PileOfAsh, 1;
+ @rossylock = true;
+
+ // Spawn underlings
+ for (.@i=0; .@i < .@mobc; .@i++) {
+ // FIXME: Penguin? Mister Prickel? Ice Goblin? Wolvern?
+ // I think all those four could be removed.
+ .@mobId=any(Bandit, RobinBandit, Skeleton, MisterPrickel, ManaGhost, Penguin, CraftyGhost, Zombie, Wolvern, SpiderGhost, IceGoblin); // Mobs lv 26~47
+ .@mob=areamonster(.@m$, .@x1, .@y1, .@x2, .@y2, strmobinfo(1, .@mobId), .@mobId, 1, .@n$);
+ // Make it aggresive
+ .@bmod=getunitdata(.@mob, UDT_MODE);
+ setunitdata(.@mob, UDT_MODE, .@bmod|4); // 4 = MD_AGGRESSIVE
+ }
+
+ // Spawn boss
+ .@mob=areamonster(.@m$, .@x1, .@y1, .@x2, .@y2, strmobinfo(1, .@boss), .@boss, 1, .@n$);
+
+ // Obain boss basic status...
+ .@bhp= getunitdata(.@mob, UDT_MAXHP);
+ .@bat1=getunitdata(.@mob, UDT_ATKMIN);
+ .@bat2=getunitdata(.@mob, UDT_ATKMAX);
+ .@bhit=getunitdata(.@mob, UDT_HIT);
+ .@bmod=getunitdata(.@mob, UDT_MODE);
+ .@bmod=.@bmod|4; // 4 = MD_AGGRESSIVE
+
+ // ...And Tweak Battle Status
+ setunitdata(.@mob, UDT_MAXHP, .@bhp*15/10);
+ setunitdata(.@mob, UDT_HP, .@bhp*15/10);
+ setunitdata(.@mob, UDT_ATKMIN, .@bat1*7/10);
+ setunitdata(.@mob, UDT_ATKMAX, .@bat2*7/10);
+ setunitdata(.@mob, UDT_HIT, .@bhit*2);
+ setunitdata(.@mob, UDT_MODE, .@bmod|32); // 32 = MD_BOSS
+
+ // Build the wall so you cannot leave :>
+ setcells getmap(), .@x3, .@y3, .@x4, .@y4, 3, "Rossy"+getcharid(0)+"Wall";
+ return true;
+}
+
+///////////////////////////////////////////////
+// Reset quest when you die
+function script RossyDeath {
+ if (getq(HurnscaldQuests_Rossy) != 16)
+ return;
+ if (@rossylock)
+ delcells("Rossy"+getcharid(0)+"Wall");
+ @rossylock=false;
+ setq2 HurnscaldQuests_Rossy, 0;
+ deltimer("#RossyQuest::OnTick1");
+ deltimer("#RossyQuest::OnTick2");
+ deltimer("#RossyQuest::OnTick3");
+ deltimer("#RossyQuest::OnTick4");
+ deltimer("#RossyQuest::OnTick5");
+ return;
+}
+
+// May reset quest when you logout
+function script RossyLogout {
+ if (getq(HurnscaldQuests_Rossy) != 16)
+ return;
+ if (@rossylock) {
+ delcells("Rossy"+getcharid(0)+"Wall");
+ @rossylock=false;
+ setq2 HurnscaldQuests_Rossy, 0;
+ }
+ // FIXME: Set timers again when you login back? =/
+ return;
+}
+
+/////////////////////////////////////////////////////////
+// Position the triggers
+
+// Begin Cave Code
+008-3-0,98,27,0 script #RossyCave01 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave01";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE1;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,199,109,0 script #RossyCave02 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave02";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE2;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,35,26,0 script #RossyCave03 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave03";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE3;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,198,193,0 script #RossyCave04 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave04";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE4;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,133,200,0 script #RossyCave05 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave05";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE5;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,27,104,0 script #RossyCave06 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave06";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE6;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,31,192,0 script #RossyCave07 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave07";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE7;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,165,26,0 script #RossyCave08 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave08";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE8;
+ end;
+}
+
+// Begin Cave Code
+008-3-0,201,69,0 script #RossyCave09 NPC_SUMMONING_CIRC,{
+ if (RossyCave(.caveid))
+ disablenpc instance_npcname(.name$);
+ close;
+
+OnInit:
+ disablenpc "#RossyCave09";
+OnInstanceInit:
+ .distance=1;
+ .caveid=ROSSY_CAVE9;
+ end;
+}
+
+// --------------------------------------------------------------------
+008-3-0,92,90,0 script Juliet NPC_TANISHA,{
+ // Check quest consistency
+ // HurnscaldQuests_Rossy
+ // (MAIN QUEST, CAVE CONTROL, INSTANCE CONTROL)
+ .@q=getq(HurnscaldQuests_Rossy);
+ .@q2=getq2(HurnscaldQuests_Rossy);
+ .@inst=getq3(HurnscaldQuests_Rossy);
+
+ if (instance_id() != .@inst)
+ end;
+ if (!.@q2)
+ end;
+
+ // A bug!
+ if (.@q != 16) {
+ disablenpc instance_npcname("Juliet", .@inst);
+ end;
+ }
+
+ // Another bug!!
+ if (!(.@q2 & ROSSY_BOSSCAVE)) {
+ disablenpc instance_npcname("Juliet", .@inst);
+ end;
+ }
+
+ // Prepare rewards
+ .@rune=any(RunestoneUruz, RunestoneRaido, RunestoneThurisaz, RunestoneKaunaz, RunestoneDagaz, RunestonePeorth);
+ .@gems=any(CrudeDiamond, CrudeRuby, CrudeEmerald, CrudeSapphire, CrudeTopaz, CrudeAmethyst);
+ inventoryplace .@rune, 1, .@gems, 1;
+
+ // Run epilogue
+ mesn;
+ mesq l("I heard some battle noises a few minutes ago. Are you here to save me?");
+ next;
+ select
+ l("Of course I'm here to save you, Rossy sent me here!");
+ mes "";
+ mesn;
+ mesc l("Juliet starts scavenging the fallen Golem.");
+ mesq l("Mommy teached me about precious gemstones. This Golem has quite a few of them.");
+ next;
+ mesn;
+ mesq l("Here you go!");
+ getitem .@gems, 1;
+ quest_item(.@rune, 1);
+ quest_xp(.maxLevel, 100000);
+ quest_jxp(.maxLevel, 10000);
+ setq HurnscaldQuests_Rossy, 17, 0, .@inst;
+ next;
+ mesn;
+ mesq l("Thanks for helping me... I'll be on my way now.");
+ next;
+ select
+ l("Go safely!"),
+ l("Do you need an escort?"),
+ l("What was following you, anyway?");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("I'll be fine, but thanks for the concern.");
+ } else if (@menu == 3) {
+ // This opens path for additional questline
+ mesn;
+ mesq l("Actually... I don't remember. I'm not sure why.");
+ next;
+ mesn;
+ mesq l("But it was big and scary! I haven't seen it since I entered this cave, though...");
+ next;
+ mesn;
+ mesq l("It probably went away after seeing your bravure, tee-hee!");
+ next;
+ mesn;
+ mesq l("I must go now. I've already spent too much time here already.");
+ }
+ disablenpc instance_npcname("Juliet", .@inst);
+ close;
+
+OnInit:
+ disablenpc "Juliet";
+ .distance=4;
+ .maxLevel=80;
+ end;
+
+OnInstanceInit:
+ disablenpc instance_npcname("Juliet");
+ .distance=4;
+ .maxLevel=90;
+ end;
+}
+
+
diff --git a/npc/008-3-1/_import.txt b/npc/008-3-1/_import.txt
new file mode 100644
index 00000000..fa138e1f
--- /dev/null
+++ b/npc/008-3-1/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-3-1: Bat Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-1/_mobs.txt",
+"npc/008-3-1/_warps.txt",
+"npc/008-3-1/arkim.txt",
diff --git a/npc/008-3-1/_mobs.txt b/npc/008-3-1/_mobs.txt
new file mode 100644
index 00000000..b741a714
--- /dev/null
+++ b/npc/008-3-1/_mobs.txt
@@ -0,0 +1,8 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-1: Bat Cave mobs
+008-3-1,42,35,7,5 monster Crafty 1018,7,1000,120000
+008-3-1,44,54,4,2 monster Crafty 1018,4,10000,75000
+008-3-1,43,39,5,2 monster Spider 1044,1,4000,8000
+008-3-1,46,53,5,2 monster Spider 1044,2,2000,7500
+008-3-1,52,31,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-1,43,25,0,0 monster Coal Vein 1048,1,600000,60000
diff --git a/npc/008-3-1/_warps.txt b/npc/008-3-1/_warps.txt
new file mode 100644
index 00000000..221789b7
--- /dev/null
+++ b/npc/008-3-1/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-1: Bat Cave warps
+008-3-1,34,34,0 warp #008-3-1_34_34 0,0,008-1,128,139
diff --git a/npc/008-3-1/arkim.txt b/npc/008-3-1/arkim.txt
new file mode 100644
index 00000000..665725bf
--- /dev/null
+++ b/npc/008-3-1/arkim.txt
@@ -0,0 +1,56 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Arkim the mad hermit and Mirak's brother
+
+008-3-1,41,34,0 script Arkim NPC_TERRY,{
+ function arkimDaily;
+ mesn;
+ mesq l("Do you want help me with bats?");
+ next;
+ select
+ l("Yes, please!"),
+ l("Bats? Actually... Why do you live here?"); // Who said they live here?
+ mes "";
+ if (@menu == 1)
+ arkimDaily();
+ mesn;
+ mesq l("Oh my, never really thought about it!");
+ next;
+ mesn;
+ mesq l("I guess mostly I enjoy experimenting with the bats here.");
+ next;
+ select
+ l("I see... Ehm... I have to go..."),
+ l("What type of experimenting?");
+ mes "";
+ if (@menu == 1)
+ close;
+ mesn;
+ mesq l("Never really thought about it either...");
+ next;
+ mesn;
+ mesc l("You watch as the hermit's old, lazy eyes open wide, and the old man comes alive with energy.");
+ mesq l("I GUESS I REALLY LIKE CUTTING THEM UP TO SEE HOW THEY WORK!! HAHAHA!");
+ next;
+ select
+ l("YOU'RE CRAZY!"),
+ l("Right... me too! Can I help?");
+ mes "";
+ if (@menu == 2)
+ arkimDaily();
+ close;
+
+function arkimDaily {
+ // DailyQuest(lvl, cost, count, item)
+ DailyQuest(20, 4, 3, BatWing);
+ close;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+
+}
+
diff --git a/npc/008-3-2/_import.txt b/npc/008-3-2/_import.txt
new file mode 100644
index 00000000..580a8f40
--- /dev/null
+++ b/npc/008-3-2/_import.txt
@@ -0,0 +1,5 @@
+// Map 008-3-2: Calamity Dungeon
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-2/_mobs.txt",
+"npc/008-3-2/_warps.txt",
+"npc/008-3-2/boss.txt",
diff --git a/npc/008-3-2/_mobs.txt b/npc/008-3-2/_mobs.txt
new file mode 100644
index 00000000..4c0dfbd0
--- /dev/null
+++ b/npc/008-3-2/_mobs.txt
@@ -0,0 +1,7 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-2: Calamity Dungeon mobs
+008-3-2,106,73,73,63 monster Cave Maggot 1027,80,30000,2500
+008-3-2,136,71,47,50 monster Thief Slime 1105,35,50000,2500
+008-3-2,101,83,73,30 monster AngryCrafty 1103,60,50000,2500
+008-3-2,100,79,32,31 monster Black Scorpion 1104,14,45000,2500
+008-3-2,94,98,11,9 monster Green Slime 1024,4,500,2500
diff --git a/npc/008-3-2/_warps.txt b/npc/008-3-2/_warps.txt
new file mode 100644
index 00000000..e69305bc
--- /dev/null
+++ b/npc/008-3-2/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-2: Calamity Dungeon warps
+008-3-2,175,19,0 warp #008-3-2_175_19 2,0,008-1,165,170
diff --git a/npc/008-3-2/boss.txt b/npc/008-3-2/boss.txt
new file mode 100644
index 00000000..0634358d
--- /dev/null
+++ b/npc/008-3-2/boss.txt
@@ -0,0 +1,43 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Description:
+// Controls the boss on 008-3-2 and the Master Book Learning
+// see npc/items/master_skillbook.txt for explanation about variables
+
+008-3-2,0,0,0 script #BossCtrl_008-3-2 NPC_HIDDEN,{
+ end;
+
+// Test server: 15 minutes only
+OnTimer900000:
+ if (!debug)
+ end;
+
+// Otherwise, respawn every hour
+OnTimer3600000:
+ stopnpctimer;
+OnInit:
+ $@MB_00832=0;
+ monster "008-3-2", 67, 30, strmobinfo(1, SpiderQueen), SpiderQueen, 1, "#BossCtrl_008-3-2::OnBossDeath";
+ end;
+
+OnBossDeath:
+ initnpctimer;
+ BossSlain(.name$, "$@MB_00832");
+ end;
+
+OnBossCheck:
+ @mb_BossId=-1;
+ // TODO: Check if you really fought or was just lurking
+ // Check if party is correct
+ if (getcharid(1) != $@MB_00832)
+ end;
+OnBegin:
+ @mb_BossId=SpiderQueen;
+ @mb_SkillId=TF_POISON;
+ @mb_ItemId=MagicFeather; // Placeholder
+ @mb_ItemAm=1;
+ addtimer(15000, "#MasterBook::OnUnset");
+ end;
+
+}
diff --git a/npc/008-3-3/_import.txt b/npc/008-3-3/_import.txt
new file mode 100644
index 00000000..96cc09c9
--- /dev/null
+++ b/npc/008-3-3/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-3-3: Bat Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-3/_mobs.txt",
+"npc/008-3-3/_warps.txt",
diff --git a/npc/008-3-3/_mobs.txt b/npc/008-3-3/_mobs.txt
new file mode 100644
index 00000000..4ff0ff2d
--- /dev/null
+++ b/npc/008-3-3/_mobs.txt
@@ -0,0 +1,9 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-3: Obelisk Cave mobs
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-3: Bat Cave mobs
+008-3-3,57,36,12,7 monster Crafty 1018,5,1000,120000
+008-3-3,31,43,4,5 monster Crafty 1018,3,1000,120000
+008-3-3,49,38,20,16 monster Cave Maggot 1027,12,500,2000
+008-3-3,60,49,5,3 monster Ratto 1005,2,35000,15000
+008-3-3,53,24,5,2 monster Ratto 1005,2,35000,15000
diff --git a/npc/008-3-3/_warps.txt b/npc/008-3-3/_warps.txt
new file mode 100644
index 00000000..871c897c
--- /dev/null
+++ b/npc/008-3-3/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-3: Obelisk Cave warps
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-3: Bat Cave warps
+008-3-3,37,57,0 warp #008-3-3_37_57 1,0,008-1,283,27
diff --git a/npc/008-3-4/_import.txt b/npc/008-3-4/_import.txt
new file mode 100644
index 00000000..e0815f43
--- /dev/null
+++ b/npc/008-3-4/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-3-4: North Mine
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-4/_mobs.txt",
+"npc/008-3-4/_warps.txt",
diff --git a/npc/008-3-4/_mobs.txt b/npc/008-3-4/_mobs.txt
new file mode 100644
index 00000000..37fb788a
--- /dev/null
+++ b/npc/008-3-4/_mobs.txt
@@ -0,0 +1,32 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-4: North Mine mobs
+008-3-4,84,55,19,25 monster Cave Maggot 1027,15,2000,20000
+008-3-4,73,100,53,17 monster Cave Maggot 1027,10,1000,15000
+008-3-4,139,58,20,21 monster Cave Maggot 1027,5,5000,25000
+008-3-4,87,78,75,12 monster Crafty 1018,12,2500,35000
+008-3-4,89,79,21,35 monster Ratto 1005,18,5000,10000
+008-3-4,133,55,16,9 monster Spider 1044,1,4000,8000
+008-3-4,49,91,29,17 monster Black Scorpion 1104,4,4000,8000
+008-3-4,138,57,16,17 monster Spider 1044,3,4000,8000
+008-3-4,54,37,16,17 monster Spider 1044,3,4000,8000
+008-3-4,85,67,49,39 monster Thief Slime 1105,3,20000,100000
+008-3-4,82,42,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-4,74,51,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-4,104,41,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-4,62,61,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-4,128,71,0,0 monster Coal Veinbloc 1071,1,600000,60000
+008-3-4,118,46,0,0 monster Coal Vein 1048,1,600000,60000
+008-3-4,108,90,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-4,72,84,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-4,47,98,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-4,50,74,0,0 monster Iron Vein 1047,1,600000,60000
+008-3-4,135,53,0,0 monster Diamond Vein 1045,1,600000,60000
+008-3-4,43,96,0,0 monster Amethyst Vein 1055,1,600000,60000
+008-3-4,102,91,0,0 monster Topaz Vein 1054,1,600000,60000
+008-3-4,33,102,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-4,154,56,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-4,53,31,0,0 monster Gem Veinbloc 1069,1,600000,60000
+008-3-4,83,44,14,9 monster Red Slime 1074,5,10000,50000
+008-3-4,115,67,13,29 monster Red Slime 1074,4,10000,50000
+008-3-4,37,79,24,27 monster Yellow Slime 1073,4,10000,50000
+008-3-4,111,67,13,29 monster Yellow Slime 1073,8,20000,75000
diff --git a/npc/008-3-4/_warps.txt b/npc/008-3-4/_warps.txt
new file mode 100644
index 00000000..d62d5fb5
--- /dev/null
+++ b/npc/008-3-4/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-4: North Mine warps
+008-3-4,88,78,0 warp #008-3-4_88_78 0,0,008-1,249,24
+008-3-4,21,85,0 warp #008-3-4_21_85 0,2,008-3-5,157,72
+008-3-4,91,119,0 warp #008-3-4_91_119 3,0,008-3-6,62,22
diff --git a/npc/008-3-5/_import.txt b/npc/008-3-5/_import.txt
new file mode 100644
index 00000000..cb743792
--- /dev/null
+++ b/npc/008-3-5/_import.txt
@@ -0,0 +1,7 @@
+// Map 008-3-5: Bandit Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-5/_mobs.txt",
+"npc/008-3-5/_warps.txt",
+"npc/008-3-5/bryant.txt",
+"npc/008-3-5/lordcave.txt",
+"npc/008-3-5/nunia.txt",
diff --git a/npc/008-3-5/_mobs.txt b/npc/008-3-5/_mobs.txt
new file mode 100644
index 00000000..5331e5e6
--- /dev/null
+++ b/npc/008-3-5/_mobs.txt
@@ -0,0 +1,12 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-5: Bandit Cave mobs
+008-3-5,87,83,22,16 monster Cave Maggot 1027,8,2000,20000
+008-3-5,79,68,54,12 monster Crafty 1018,12,2500,35000
+008-3-5,71,62,49,39 monster Thief Slime 1105,3,20000,100000
+008-3-5,90,70,13,29 monster Yellow Slime 1073,8,20000,75000
+008-3-5,79,82,21,15 monster Bandit 1063,3,2000,20000
+008-3-5,74,66,38,21 monster Snake 1075,3,10000,100000
+008-3-5,54,41,26,21 monster Robin Bandit 1064,2,2000,20000
+008-3-5,44,51,13,33 monster Cave Maggot 1027,7,2000,20000
+008-3-5,49,41,38,21 monster Bandit 1063,2,2000,20000
+008-3-5,133,72,24,9 monster Ratto 1005,6,5000,10000
diff --git a/npc/008-3-5/_warps.txt b/npc/008-3-5/_warps.txt
new file mode 100644
index 00000000..be81f002
--- /dev/null
+++ b/npc/008-3-5/_warps.txt
@@ -0,0 +1,6 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-5: Bandit Cave warps
+008-3-5,158,72,0 warp #008-3-5_158_72 0,2,008-3-4,22,85
+008-3-5,109,67,0 warp #008-3-5_109_67 0,2,008-3-5,101,68
+008-3-5,102,68,0 warp #008-3-5_102_68 0,2,008-3-5,110,67
+008-3-5,92,108,0 warp #008-3-5_92_108 0,0,008-1,109,83
diff --git a/npc/008-3-5/bryant.txt b/npc/008-3-5/bryant.txt
new file mode 100644
index 00000000..4199c484
--- /dev/null
+++ b/npc/008-3-5/bryant.txt
@@ -0,0 +1,79 @@
+// TMW2 Script.
+// Author:
+// Jesusalva
+// Description:
+// Part of Helena's quest
+// Gives spoilers about what Jesusalva plans in doing with Bryant
+
+008-3-5,101,85,0 script Bryant NPC_CRASMANDE,{
+ function bryantBanditLord;
+ function bryantSilverKey;
+ function bryantComplete;
+ .@q=getq(HurnscaldQuest_Bandits);
+ if (.@q == 5) bryantSilverKey();
+ if (.@q == 6) bryantBanditLord();
+ if (.@q >= 7) bryantComplete();
+ mesn;
+ mesq l("Welcome.");
+ next;
+ mesn;
+ mesq l("I'm looking everywhere for the bandit leader. I can't seem to find him. So I stopped here to rest a bit.");
+ close;
+
+function bryantSilverKey {
+ mesn;
+ mesq l("Don't say anything, I can smell the scent of Lena's hair on you.");
+ next;
+ inventoryplace PiberriesInfusion, 3;
+ getitem PiberriesInfusion, 3;
+ setq HurnscaldQuest_Bandits, 6;
+ mesn;
+ mesq l("I guess she sent you to kill the Bandit Lord, right? I'll lure him for you.");
+ next;
+ mesn;
+ mesq l("It is pretty close to here. I advise you to use a good sword, and heal yourself often.");
+ next;
+ mesn;
+ mesq l("I will give you 3 @@. Use them on this fight, or you're doomed to fail.", getitemlink(PiberriesInfusion));
+ close;
+}
+
+function bryantBanditLord {
+ mesn;
+ mesq l("What are you waiting for? Go kill the bandit lord.");
+ next;
+ mesn strcharinfo(0);
+ select
+ l("I'm going, don't worry."),
+ l("There was nobody on the Bandit Lord's room.");
+ if (@menu == 1)
+ close;
+ mes "";
+ mesn;
+ mesq l("...Have you ever gone there yet?");
+ next;
+ mesn;
+ mesq l("Go kill the Bandit Lord!");
+ close;
+}
+
+function bryantComplete {
+ mesn;
+ mesq l("Good job defeating the Bandit Lord.");
+ close;
+}
+
+OnInit:
+ /*
+ .@npcId = getnpcid(.name$);
+ setunitdata(.@npcId, UDT_HEADTOP, FairyHat);
+ setunitdata(.@npcId, UDT_HEADMIDDLE, ForestArmor);
+ setunitdata(.@npcId, UDT_HEADBOTTOM, JeansChaps);
+ setunitdata(.@npcId, UDT_WEAPON, DeepBlackBoots);
+ setunitdata(.@npcId, UDT_HAIRSTYLE, 24);
+ setunitdata(.@npcId, UDT_HAIRCOLOR, 1);
+ */
+
+ .distance = 5;
+ end;
+}
diff --git a/npc/008-3-5/lordcave.txt b/npc/008-3-5/lordcave.txt
new file mode 100644
index 00000000..906cd8ad
--- /dev/null
+++ b/npc/008-3-5/lordcave.txt
@@ -0,0 +1,101 @@
+// TMW2 Script
+// Author:
+// Jesusalva
+// FIXME:
+// Create a party instance for this
+
+008-3-5,83,49,0 script #BanditLordDen NPC_HIDDEN,0,5,{
+ function lordCleanup;
+ end;
+
+function lordCleanup {
+ // Bug
+ if (!.lock) {
+ consolemes(CONSOLEMES_ERROR, "No lock passed to Lord Cave during cleanup");
+ end;
+ }
+
+ // Cleanup
+ .lock = false;
+ delcells "BanditLordDenWall";
+ killmonster("008-3-5", "#BanditLordDen::OnLordDeath");
+ stopnpctimer;
+ return;
+}
+
+OnInit:
+ .maxLevel = 55;
+ .lock=false;
+ end;
+
+OnTouch:
+ .@q=getq(HurnscaldQuest_Bandits);
+ if (.@q != 6) end;
+
+ // Oooh, we got a challenger!
+
+ // But the Lord is busy? Oh well, try again later
+ if (.lock) {
+ dispbottom l("%s came here first, you should wait for them.", strcharinfo(0, "Someone", .lock));
+ slide 92, 52;
+ end;
+ }
+
+ // Block the NPC
+ .lock=getcharid(3);
+ slide 80, 49;
+
+ // Block the passage
+ mapannounce "008-3-5", "A minor earthquake happens.", bc_map;
+ setcells "008-3-5", 82, 48, 83, 51, 2, "BanditLordDenWall";
+ initnpctimer;
+
+ // Summon
+ if (mobcount("008-3-5", "#BanditLordDen::OnLordDeath") == 0)
+ monster "008-3-5", 48, 35, "Bandit Lord", BanditLord, 1, "#BanditLordDen::OnLordDeath";
+ end;
+
+OnLordDeath:
+ // Unlock
+ lordCleanup();
+
+ // If killed by a monster, GM, whatever, abort
+ if (!playerattached())
+ end;
+
+ // Complete quest (if PC is attached and doing quest)
+ .@q=getq(HurnscaldQuest_Bandits);
+ if (.@q == 6 && !ispcdead()) {
+ setq HurnscaldQuest_Bandits, 7;
+ quest_xp(.maxLevel, 2500);
+ dispbottom l("Phew! The Bandit Lord was killed.");
+ } else {
+ dispbottom l("I killed the Bandit Lord! ...Why I did that, again?");
+ }
+ end;
+
+OnTimer5000:
+ .@pc=attachrid(.lock);
+
+ // Player logged out
+ if (!.@pc) {
+ lordCleanup();
+ end;
+ }
+
+ // Player killed in combat
+ if (ispcdead()) {
+ lordCleanup();
+ end;
+ }
+
+ // Player changed map
+ if (getmap() != "008-3-5") {
+ lordCleanup();
+ end;
+ }
+
+ // Battle ongoing, restart timer
+ initnpctimer;
+ end;
+}
diff --git a/npc/008-3-5/nunia.txt b/npc/008-3-5/nunia.txt
new file mode 100644
index 00000000..cd12a085
--- /dev/null
+++ b/npc/008-3-5/nunia.txt
@@ -0,0 +1,81 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Nunia, Henry's friend and Woodland's master thief.
+// THIS IS A PLACEHOLDER!
+
+008-3-5,35,65,0 script Nunia NPC_NUNIA,{
+ function nuniaIntruder;
+ function nuniaHenry;
+ function nuniaBegin;
+
+ // What do we have here?
+ .@q=getq(ThiefQuests_Artis);
+ switch (.@q) {
+ case 7:
+ nuniaHenry();
+ break;
+ case 8:
+ case 9:
+ nuniaBegin();
+ // TODO: Script control; Transfer quest variable authority
+ break;
+ default:
+ nuniaIntruder();
+ break;
+ }
+ close;
+
+///////////////////////////////////////////////////////////////////////////////
+function nuniaIntruder {
+ speech
+ l("Who dares to enter this cave? Who are you?"),
+ l("At least, you look peaceful."),
+ l("Let's do like this: You leave me alone, and I don't mess with you. Deal?");
+ select
+ l("Deal."),
+ l("No deal, I'm going to report you to authorities!");
+ mes "";
+ // Some meta option/dialog to improve the immersion
+ if (@menu == 2) {
+ mesn;
+ mesq l("There's only one problem, you know...");
+ next;
+ mesn;
+ mesq l("The dead can't speak.");
+ percentheal -100, -100;
+ }
+ return;
+}
+
+function nuniaHenry {
+ mesn;
+ mesq l("Your smell... Did Henry sent you here? How cute of him!");
+ next;
+ mesn;
+ mesq l("I've raised too much suspicion, so my friends told me to lay low for a while.");
+ next;
+ mesn;
+ mesq l("The Brotherhood is watching our movements, they already suspect who is a member and who isn't, but they don't know for sure.");
+ next;
+ mesn;
+ mesq l("Therefore, we had to cut off our connection with Artis. Don't want Brotherhood to find the secrets of our structure.");
+ setq1 ThiefQuests_Artis, 8;
+ return;
+}
+
+function nuniaBegin {
+ speech
+ l("Who dares to enter this cave? Who are you?"),
+ l("At least, you look peaceful. And I see by your fingers that you can deal with lockpicks."),
+ l("I am going to teach you all what a thief needs to know, later"),
+ l("Call for Micksha and Jesusalva to implement all this, please."),
+ l("And Tanveer, our president in Tulimshar, should be able to give you even more training. If you manage to find our headquarters, of course, hahaha!");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-3-6/_import.txt b/npc/008-3-6/_import.txt
new file mode 100644
index 00000000..41b51532
--- /dev/null
+++ b/npc/008-3-6/_import.txt
@@ -0,0 +1,4 @@
+// Map 008-3-6: Hurnscald Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-3-6/_mobs.txt",
+"npc/008-3-6/_warps.txt",
diff --git a/npc/008-3-6/_mobs.txt b/npc/008-3-6/_mobs.txt
new file mode 100644
index 00000000..91e614fe
--- /dev/null
+++ b/npc/008-3-6/_mobs.txt
@@ -0,0 +1,11 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-6: Hurnscald Cave mobs
+008-3-6,54,73,18,19 monster Red Slime 1074,5,10000,50000
+008-3-6,67,44,35,8 monster Yellow Slime 1073,3,10000,50000
+008-3-6,86,43,23,22 monster Red Slime 1074,4,10000,50000
+008-3-6,86,76,24,13 monster Yellow Slime 1073,4,10000,50000
+008-3-6,75,65,24,27 monster Cave Maggot 1027,8,2000,20000
+008-3-6,56,62,10,7 monster Ratto 1005,3,5000,10000
+008-3-6,71,77,10,7 monster Ratto 1005,3,5000,10000
+008-3-6,96,53,15,11 monster Ratto 1005,4,5000,10000
+008-3-6,95,63,15,21 monster Black Scorpion 1104,1,4000,8000
diff --git a/npc/008-3-6/_warps.txt b/npc/008-3-6/_warps.txt
new file mode 100644
index 00000000..95dd673a
--- /dev/null
+++ b/npc/008-3-6/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-3-6: Hurnscald Cave warps
+008-3-6,64,21,0 warp #008-3-6_64_21 3,0,008-3-4,90,118
diff --git a/npc/009-1/_import.txt b/npc/009-1/_import.txt
new file mode 100644
index 00000000..0d4e3164
--- /dev/null
+++ b/npc/009-1/_import.txt
@@ -0,0 +1,10 @@
+// Map 009-1: Swamp
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-1/_mobs.txt",
+"npc/009-1/_warps.txt",
+"npc/009-1/blackwin.txt",
+"npc/009-1/forwin.txt",
+"npc/009-1/hamond.txt",
+"npc/009-1/soul-menhir.txt",
+"npc/009-1/thurstan.txt",
+"npc/009-1/wateranimation.txt",
diff --git a/npc/009-1/_mobs.txt b/npc/009-1/_mobs.txt
new file mode 100644
index 00000000..278be1b7
--- /dev/null
+++ b/npc/009-1/_mobs.txt
@@ -0,0 +1,33 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-1: Swamp mobs
+009-1,190,74,53,40 monster Silkworm 1040,12,4500,6000
+009-1,152,116,48,43 monster Forest Maggot 1028,20,3600,12000
+009-1,89,116,43,31 monster Grass Snake 1042,5,6000,24000
+009-1,192,155,43,31 monster Grass Snake 1042,7,3000,12000
+009-1,228,64,17,32 monster Log Head 1031,4,5000,30000
+009-1,168,95,14,9 monster Bandit 1063,2,9000,18000
+009-1,115,150,45,26 monster Thief Slime 1105,5,11500,45000
+009-1,185,179,45,20 monster Blub 1008,4,60000,120000
+009-1,128,144,77,47 monster Green Slime 1024,10,10000,30000
+009-1,63,175,30,15 monster Little Green Slime 1025,5,10000,30000
+009-1,84,111,30,15 monster Little Green Slime 1025,5,10000,50000
+009-1,228,139,13,12 monster Mana Ghost 1101,2,10000,30000
+009-1,45,182,13,12 monster Mana Ghost 1101,4,10000,60000
+009-1,69,185,31,9 monster Skeleton 1084,4,6000,24000
+009-1,142,159,84,20 monster Swampling 1109,10,30000,60000
+009-1,162,99,17,15 monster Robin Bandit 1064,2,9000,18000
+009-1,184,48,38,13 monster Spiky Mushroom 1049,4,3000,12000
+009-1,103,86,31,27 monster Big Frog 1087,3,6000,60000
+009-1,85,118,49,43 monster Small Frog 1086,8,3000,30000
+009-1,152,165,44,40 monster Big Frog 1087,5,6000,75000
+009-1,188,188,49,18 monster Small Frog 1086,7,3000,30000
+009-1,228,65,16,8 monster Spider 1044,2,4000,8000
+009-1,209,58,16,28 monster Grass Snake 1042,4,3000,12000
+009-1,232,79,3,12 monster Wicked Mushroom 1050,3,6000,12000
+009-1,124,64,3,12 monster Wicked Mushroom 1050,7,3000,12000
+009-1,214,173,13,12 monster Zombie 1118,1,48000,120000
+009-1,37,181,13,12 monster Water Wisp 1116,3,10000,60000
+009-1,66,182,13,12 monster Fire Wisp 1115,1,10000,60000
+009-1,131,193,13,12 monster Green Slime Progenitor 1097,1,48000,120000
+009-1,149,174,84,19 monster Mud Slime 1096,4,30000,60000
+009-1,61,109,16,32 monster Serqet 1119,2,12000,60000
diff --git a/npc/009-1/_warps.txt b/npc/009-1/_warps.txt
new file mode 100644
index 00000000..a5300fba
--- /dev/null
+++ b/npc/009-1/_warps.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-1: Swamp warps
+009-1,181,31,0 warp #009-1_181_31 1,0,008-1-1,180,197
+009-1,249,48,0 warp #009-1_249_48 0,0,008-1,23,216
+009-1,175,77,0 warp #009-1_175_77 1,0,009-2-1,34,44
+009-1,161,90,0 warp #009-1_161_90 1,0,009-2-0,31,39
+009-1,184,101,0 warp #009-1_184_101 0,0,009-2-2,32,39
+009-1,35,168,0 warp #009-1_35_168 1,0,009-2-3,41,39
+009-1,67,159,0 warp #009-1_67_159 0,0,009-2-6,29,35
+009-1,64,186,0 warp #009-1_64_186 0,0,009-2-7,29,35
+009-1,90,159,0 warp #009-1_90_159 0,0,009-2-8,29,40
+009-1,196,96,0 warp #009-1_196_96 1,0,009-2-9,34,43
+009-1,95,192,0 warp #009-1_95_192 0,0,009-2-12,28,43
+009-1,206,148,0 warp #009-1_206_148 0,0,009-2-15,28,41
+009-1,213,147,0 warp #009-1_213_147 1,0,009-2-15,43,40
diff --git a/npc/009-1/blackwin.txt b/npc/009-1/blackwin.txt
new file mode 100644
index 00000000..7ad7f39b
--- /dev/null
+++ b/npc/009-1/blackwin.txt
@@ -0,0 +1,30 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Blackwin, guardian of Asphodel Moors, disciple of Golbenez. Twice. It is magic.
+// THIS IS A PLACEHOLDER!
+
+009-1,75,144,0 script Blackwin#1 NPC_UNDEAD_GUARD,{
+ speech
+ l("..."),
+ l("Heed my warning, young %s. My master will suffer no fools here.", get_race(GETRACE_RACE)),
+ l("He created this as a place of leisure, and we are here to ensure that it remains undisturbed.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+009-1,105,173,0 script Blackwin#2 NPC_UNDEAD_GUARD,{
+ speech
+ l("..."),
+ l("Heed my warning, young %s. My master will suffer no fools here.", get_race(GETRACE_RACE)),
+ l("He created this as a place of leisure, and we are here to ensure that it remains undisturbed.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-1/forwin.txt b/npc/009-1/forwin.txt
new file mode 100644
index 00000000..4b134f03
--- /dev/null
+++ b/npc/009-1/forwin.txt
@@ -0,0 +1,24 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Martha, sort of Brotherhood Leader in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+009-1,48,171,0 script Forwin NPC_UNDEAD_GUARD,{
+ mesn;
+ mesq l("%s...", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("I am your father...");
+ next;
+ mesc l("There is an awkward pause, and then the guard bursts out laughing.");
+ mes "";
+ mesn;
+ mesq l("Just kidding! Can you imagine Golbenez's reaction if we had such puny offspring?");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-1/hamond.txt b/npc/009-1/hamond.txt
new file mode 100644
index 00000000..25824589
--- /dev/null
+++ b/npc/009-1/hamond.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Hamond, Reid's Husband
+// THIS IS A PLACEHOLDER!
+
+009-1,37,170,0 script Hamond NPC_HAMOND,{
+ speech
+ l("Hello, my name is Hamond."),
+ l("I run the inn together with my beautiful wife Reid."),
+ l("If there is anything I can do for you, please let me know.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-1/soul-menhir.txt b/npc/009-1/soul-menhir.txt
new file mode 100644
index 00000000..76c5be11
--- /dev/null
+++ b/npc/009-1/soul-menhir.txt
@@ -0,0 +1,7 @@
+// The Mana World scripts.
+// Description:
+// place of power, mana refills faster when sitting nearby
+
+// Soul Menhir#town_rate_dist_timer
+009-1,51,173,0 duplicate(Soul Menhir) Soul Menhir#moor_1_7_300 NPC_NO_SPRITE
+
diff --git a/npc/009-1/thurstan.txt b/npc/009-1/thurstan.txt
new file mode 100644
index 00000000..3eb8fbdc
--- /dev/null
+++ b/npc/009-1/thurstan.txt
@@ -0,0 +1,22 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Thurstan, a headless man (because Golbenez, for sure)
+// THIS IS A PLACEHOLDER!
+
+009-1,84,169,0 script Thurstan NPC_THURSTAN,{
+ mesc l("You see a man, propped up against the foot of the tree.");
+ mesc l("In his hand, he is holding what you assume to be his own head.");
+ next;
+ mesc l("You jump back a bit, startled, as the head starts talking to you!");
+ mesc l("It's a little strange watching him talk, but it's better than looking at what's left of his neck.");
+ next;
+ mesn;
+ mesq l("Greetings! Do you have any duck tape?"); // Perhaps duct tape?
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-1/wateranimation.txt b/npc/009-1/wateranimation.txt
new file mode 100644
index 00000000..d6912af7
--- /dev/null
+++ b/npc/009-1/wateranimation.txt
@@ -0,0 +1,10 @@
+// The Mana World scripts.
+// Description:
+// Water animations, splash, fishes, etc...
+
+009-1,109,56,0 duplicate(#fish_river) #swamp_fish01 NPC_WATER_SPLASH
+009-1,114,74,0 duplicate(#fish_river) #swamp_fish02 NPC_WATER_SPLASH
+009-1,97,82,0 duplicate(#fish_river) #swamp_fish03 NPC_WATER_SPLASH
+009-1,97,74,0 duplicate(#fish_river) #swamp_fish04 NPC_WATER_SPLASH
+009-1,110,65,0 duplicate(#fish_river) #swamp_fish05 NPC_WATER_SPLASH
+
diff --git a/npc/009-2-0/_import.txt b/npc/009-2-0/_import.txt
new file mode 100644
index 00000000..9054121f
--- /dev/null
+++ b/npc/009-2-0/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-0: Soren's Home
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-0/_warps.txt",
diff --git a/npc/009-2-0/_warps.txt b/npc/009-2-0/_warps.txt
new file mode 100644
index 00000000..56769a5c
--- /dev/null
+++ b/npc/009-2-0/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-0: Soren's Home warps
+009-2-0,32,40,0 warp #009-2-0_32_40 1,0,009-1,160,91
diff --git a/npc/009-2-1/_import.txt b/npc/009-2-1/_import.txt
new file mode 100644
index 00000000..2c025b07
--- /dev/null
+++ b/npc/009-2-1/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-1: Migglemire Townhall
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-1/_warps.txt",
diff --git a/npc/009-2-1/_warps.txt b/npc/009-2-1/_warps.txt
new file mode 100644
index 00000000..8ecaf6a3
--- /dev/null
+++ b/npc/009-2-1/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-1: Migglemire Townhall warps
+009-2-1,35,45,0 warp #009-2-1_35_45 1,0,009-1,174,78
diff --git a/npc/009-2-10/_import.txt b/npc/009-2-10/_import.txt
new file mode 100644
index 00000000..964d28a6
--- /dev/null
+++ b/npc/009-2-10/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-10: Migglemire Crypt Level 2
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-10/_warps.txt",
diff --git a/npc/009-2-10/_warps.txt b/npc/009-2-10/_warps.txt
new file mode 100644
index 00000000..4a28845e
--- /dev/null
+++ b/npc/009-2-10/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-10: Migglemire Crypt Level 2 warps
+009-2-10,41,33,0 warp #009-2-10_41_33 2,0,009-2-9,40,40
+009-2-10,51,41,0 warp #009-2-10_51_41 2,0,009-2-11,29,28
diff --git a/npc/009-2-11/_import.txt b/npc/009-2-11/_import.txt
new file mode 100644
index 00000000..34f7cbd6
--- /dev/null
+++ b/npc/009-2-11/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-11: Migglemire Crypt Boss Chamber
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-11/_warps.txt",
diff --git a/npc/009-2-11/_warps.txt b/npc/009-2-11/_warps.txt
new file mode 100644
index 00000000..57985373
--- /dev/null
+++ b/npc/009-2-11/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-11: Migglemire Crypt Boss Chamber warps
+009-2-11,29,27,0 warp #009-2-11_29_27 2,0,009-2-10,51,40
diff --git a/npc/009-2-12/_import.txt b/npc/009-2-12/_import.txt
new file mode 100644
index 00000000..329928e0
--- /dev/null
+++ b/npc/009-2-12/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-12: Asphodel Moor Crypt Ground Level
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-12/_warps.txt",
diff --git a/npc/009-2-12/_warps.txt b/npc/009-2-12/_warps.txt
new file mode 100644
index 00000000..23182569
--- /dev/null
+++ b/npc/009-2-12/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-12: Asphodel Moor Crypt Ground Level warps
+009-2-12,29,44,0 warp #009-2-12_29_44 1,0,009-1,95,793
+009-2-12,41,44,0 warp #009-2-12_41_44 1,0,009-2-13,60,46
diff --git a/npc/009-2-13/_import.txt b/npc/009-2-13/_import.txt
new file mode 100644
index 00000000..9d732c47
--- /dev/null
+++ b/npc/009-2-13/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-13: Asphodel Moor Crypt Level 2
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-13/_warps.txt",
diff --git a/npc/009-2-13/_warps.txt b/npc/009-2-13/_warps.txt
new file mode 100644
index 00000000..9b003dca
--- /dev/null
+++ b/npc/009-2-13/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-13: Asphodel Moor Crypt Level 2 warps
+009-2-13,60,45,0 warp #009-2-13_60_45 2,0,009-2-12,40,43
+009-2-13,41,29,0 warp #009-2-13_41_29 0,2,009-2-14,61,37
diff --git a/npc/009-2-14/_import.txt b/npc/009-2-14/_import.txt
new file mode 100644
index 00000000..0c78394b
--- /dev/null
+++ b/npc/009-2-14/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-14: Asphodel Moor Crypt Boss Chamber
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-14/_warps.txt",
diff --git a/npc/009-2-14/_warps.txt b/npc/009-2-14/_warps.txt
new file mode 100644
index 00000000..6da17a0d
--- /dev/null
+++ b/npc/009-2-14/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-14: Asphodel Moor Crypt Boss Chamber warps
+009-2-14,62,37,0 warp #009-2-14_62_37 0,2,009-2-13,42,29
diff --git a/npc/009-2-15/_import.txt b/npc/009-2-15/_import.txt
new file mode 100644
index 00000000..6a79a87b
--- /dev/null
+++ b/npc/009-2-15/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-15: Chapel
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-15/_warps.txt",
diff --git a/npc/009-2-15/_warps.txt b/npc/009-2-15/_warps.txt
new file mode 100644
index 00000000..00e194e0
--- /dev/null
+++ b/npc/009-2-15/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-15: Chapel warps
+009-2-15,44,41,0 warp #009-2-15_44_41 1,0,009-1,212,148
+009-2-15,28,42,0 warp #009-2-15_28_42 0,0,009-1,206,149
+009-2-15,26,32,0 warp #009-2-15_26_32 2,0,009-2-16,27,35
diff --git a/npc/009-2-16/_import.txt b/npc/009-2-16/_import.txt
new file mode 100644
index 00000000..6da0f6d3
--- /dev/null
+++ b/npc/009-2-16/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-16: Chapel Tower 1st Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-16/_warps.txt",
diff --git a/npc/009-2-16/_warps.txt b/npc/009-2-16/_warps.txt
new file mode 100644
index 00000000..00ddcacb
--- /dev/null
+++ b/npc/009-2-16/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-16: Chapel Tower 1st Floor warps
+009-2-16,33,36,0 warp #009-2-16_33_36 1,0,009-2-17,26,35
+009-2-16,27,36,0 warp #009-2-16_27_36 2,0,009-2-15,26,33
diff --git a/npc/009-2-17/_import.txt b/npc/009-2-17/_import.txt
new file mode 100644
index 00000000..b7303201
--- /dev/null
+++ b/npc/009-2-17/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-17: Chapel Tower 2nd Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-17/_warps.txt",
diff --git a/npc/009-2-17/_warps.txt b/npc/009-2-17/_warps.txt
new file mode 100644
index 00000000..a86a0a91
--- /dev/null
+++ b/npc/009-2-17/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-17: Chapel Tower 2nd Floor warps
+009-2-17,33,36,0 warp #009-2-17_33_36 1,0,009-2-18,67,160
+009-2-17,27,36,0 warp #009-2-17_27_36 1,0,009-2-16,33,35
diff --git a/npc/009-2-18/_import.txt b/npc/009-2-18/_import.txt
new file mode 100644
index 00000000..ec6f6a4d
--- /dev/null
+++ b/npc/009-2-18/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-18: Chapel Tower Top
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-18/_warps.txt",
diff --git a/npc/009-2-18/_warps.txt b/npc/009-2-18/_warps.txt
new file mode 100644
index 00000000..76d9c59a
--- /dev/null
+++ b/npc/009-2-18/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-18: Chapel Tower Top warps
+009-2-18,27,36,0 warp #009-2-18_27_36 1,0,009-2-17,33,35
diff --git a/npc/009-2-2/_import.txt b/npc/009-2-2/_import.txt
new file mode 100644
index 00000000..84a2b757
--- /dev/null
+++ b/npc/009-2-2/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-2: Gardenhouse
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-2/_warps.txt",
diff --git a/npc/009-2-2/_warps.txt b/npc/009-2-2/_warps.txt
new file mode 100644
index 00000000..950b9671
--- /dev/null
+++ b/npc/009-2-2/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-2: Gardenhouse warps
+009-2-2,32,40,0 warp #009-2-2_32_40 0,0,009-1,184,102
diff --git a/npc/009-2-3/_import.txt b/npc/009-2-3/_import.txt
new file mode 100644
index 00000000..3fa1bf43
--- /dev/null
+++ b/npc/009-2-3/_import.txt
@@ -0,0 +1,6 @@
+// Map 009-2-3: Reid's Inn
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-3/_warps.txt",
+"npc/009-2-3/barbara.txt",
+"npc/009-2-3/chef.txt",
+"npc/009-2-3/reid.txt",
diff --git a/npc/009-2-3/_warps.txt b/npc/009-2-3/_warps.txt
new file mode 100644
index 00000000..a61ea11b
--- /dev/null
+++ b/npc/009-2-3/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-3: Reid's Inn warps
+009-2-3,42,40,0 warp #009-2-3_42_40 1,0,009-1,34,169
+009-2-3,56,28,0 warp #009-2-3_56_28 0,0,009-2-5,55,31
+009-2-3,56,42,0 warp #009-2-3_56_42 0,0,009-2-4,56,39
diff --git a/npc/009-2-3/barbara.txt b/npc/009-2-3/barbara.txt
new file mode 100644
index 00000000..b555b472
--- /dev/null
+++ b/npc/009-2-3/barbara.txt
@@ -0,0 +1,17 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// ???
+// THIS IS A PLACEHOLDER!
+
+009-2-3,41,30,0 script Barbara Grey NPC_UNDEAD_RECPTION,{
+ speech
+ l("Don't be shy, darling."),
+ l("Come on in and have a nice long... long slumber...");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-3/chef.txt b/npc/009-2-3/chef.txt
new file mode 100644
index 00000000..6b5ca4c0
--- /dev/null
+++ b/npc/009-2-3/chef.txt
@@ -0,0 +1,91 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// The nameless chef of Reid's Inn
+
+009-2-3,27,41,0 script Chef#Reid NPC_REIDCHEF,{
+ function cookingIntro;
+ function cookingDeal;
+ .@q=getq(General_Cooking);
+ mesn;
+ mesq l("You're in the way. Get moving!");
+ // TODO: Shop option
+ if (.@q == 5)
+ cookingIntro();
+ if (.@q == 9)
+ cookingDeal();
+ close;
+
+function cookingIntro {
+ .@q2=getq2(General_Cooking);
+ next;
+ select
+ l("Okay, okay..."),
+ l("I've heard you were a great chef and wanted to learn a recipe.");
+ mes "";
+ if (@menu == 1)
+ return;
+ mesn;
+ mesq l("Do I look like charity to you? I'm undead, you know?");
+ next;
+ mesn;
+ mesq l("Actually, the food quality here is horrible. I'm glad I'm undead or I would not eat here.");
+ next;
+ mesn;
+ mesq l("It is all \"fancy\" stuff, I don't even know if that could be of any nourishment for the living, and tastes like rotten. Well, figures. Undead town.");
+ next;
+ mesn;
+ mesq l("What about the following deal: You bring me some tasty food, and I give you some tasty recipe from before I became undead?");
+ next;
+ select
+ l("Deal"),
+ l("No Deal");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Smart choice, still-living person.");
+ return;
+ }
+ setq1 General_Cooking, 6;
+ mesn;
+ mesq l("Hah, you'll regret it. Bring me %d %s, before Golbenez finds out about our silly agreement.", .amount, getitemlink(.@q2 == VEGAN ? MananaSandwich : PioulegSandwich));
+ return;
+}
+
+function cookingDeal {
+ .@q2=getq2(General_Cooking);
+ .@item=(.@q2 == VEGAN ? MananaSandwich : PioulegSandwich);
+ .@recp=(.@q2 == CARNIVOROUS ? CraftMoubooStew : CraftSquirrelStew);
+ .@reit=(.@q2 == CARNIVOROUS ? MoubooStew : SquirrelStew);
+ next;
+ select
+ l("Okay, okay..."),
+ l("I wanted to give you the %d sandwiches you asked.", .amount);
+ mes "";
+ if (countitem(.@item) < .amount) {
+ mesn;
+ mesq l("Wha- Do you think I'm stupid?");
+ next;
+ mesn;
+ mesq l("You better get out of here, before I turn you into stew!");
+ return;
+ }
+ delitem .@item, .amount;
+ setq1 General_Cooking, 10;
+ RECIPES[.@recp]=true;
+ mesn;
+ mesq l("Eh, not bad. So, here is the %s recipe, from when I was living. It was a blast.", getitemlink(.@reit));
+ next;
+ mesn;
+ mesq l("Now begone and stop disrupting my work!");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ .amount = 10;
+ end;
+
+}
+
diff --git a/npc/009-2-3/reid.txt b/npc/009-2-3/reid.txt
new file mode 100644
index 00000000..4445759b
--- /dev/null
+++ b/npc/009-2-3/reid.txt
@@ -0,0 +1,22 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Reid is Hamond's wife. She secretly had an affair with Savaric.
+// THIS IS A PLACEHOLDER!
+
+009-2-3,42,30,0 script Reid NPC_REID,{
+ mesc l("You see a dead woman lying on the floor and something that appears to be her ghost floating above her dead body.");
+ next;
+ mesn l("Ghost");
+ mesq l("He- I - What - Oh -");
+ mesc l("The womans ghost seems to be confused.");
+ next;
+ mesn;
+ mesq l("Oh, I'm sorry. Welcome to Reid's Inn. My name is Reid, I am the innkeeper of this wonderful place of leisure. Please enjoy your visit here!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-4/_import.txt b/npc/009-2-4/_import.txt
new file mode 100644
index 00000000..0c8dd0be
--- /dev/null
+++ b/npc/009-2-4/_import.txt
@@ -0,0 +1,5 @@
+// Map 009-2-4: Reid's Inn Basement
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-4/_warps.txt",
+"npc/009-2-4/aldred.txt",
+"npc/009-2-4/golbenez.txt",
diff --git a/npc/009-2-4/_warps.txt b/npc/009-2-4/_warps.txt
new file mode 100644
index 00000000..d7773e5f
--- /dev/null
+++ b/npc/009-2-4/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-4: Reid's Inn Basement warps
+009-2-4,56,38,0 warp #009-2-4_56_38 0,0,009-2-3,56,41
diff --git a/npc/009-2-4/aldred.txt b/npc/009-2-4/aldred.txt
new file mode 100644
index 00000000..9a340913
--- /dev/null
+++ b/npc/009-2-4/aldred.txt
@@ -0,0 +1,17 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Aldred is Hamond's and Reid's son.
+// THIS IS A PLACEHOLDER!
+
+009-2-4,50,35,0 script Aldred NPC_UNDEAD_WEPPER,{
+ mesn;
+ mesq l("Waaahhhhh!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/009-2-4/golbenez.txt b/npc/009-2-4/golbenez.txt
new file mode 100644
index 00000000..2fda0314
--- /dev/null
+++ b/npc/009-2-4/golbenez.txt
@@ -0,0 +1,51 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description (SPOILERS):
+// Golbenez, a very dangerous, evil AND cruel woman from a parallel dimension.
+// After being summoned by Savaric, she betrayed him and made the Inn in her
+// leisure place. Later, she invaded The Mana World, kidnapped Santa to obtain
+// enough spiritual energy, and brought the whole Inn to The Mana World.
+//
+// At time of writing, it is unknown how Asphodel Moors came to be.
+// It is possible that Golbenez cannot return to her original dimension,
+// And it is also possible that her attempt resulted in she ending up in TMW.
+//
+// (It is also possible that due the summoning ritual, Golbenez is somehow
+// bound to Savaric and like monster summons, cannot remain in existence if
+// the summoner is dead. If proven, this could change completely the reason
+// why Golbenez kept the whole Inn alive and brought it with her.)
+//
+// At time of writing, It is unknown if she is alive, undead, or neither and
+// is a spirit.
+// Other NPCs cannot comprehend and will always treat her as a "him".
+// Most other NPCs cannot say Golbenez' name properly, and will say "Golbanez",
+// "Galvanes", "Gilbenos", "Golbinos" and/or "Galvanis".
+// This is part of lore, please do not try to "fix" it in other NPCs as well.
+// THIS IS A PLACEHOLDER!
+
+009-2-4,30,32,0 script Golbenez NPC_GOLBENEZ,{
+ mesn;
+ mesq l("How do you like my place of leisure, mortal?");
+ select
+ l("What is this place? Why is it full of dead people?"),
+ l("You look different here. Nice horns."),
+ l("I'm enjoying myself, thanks for asking.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("Mortal, this is beyond your comprehension. Do not worry about it and enjoy your time.");
+ break;
+ case 2:
+ mesn;
+ mesc l("%s bursts out with laughter.", .name$);
+ mesq l("Mortals! They never stop surprising me.");
+ break;
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-5/_import.txt b/npc/009-2-5/_import.txt
new file mode 100644
index 00000000..fcaccd3f
--- /dev/null
+++ b/npc/009-2-5/_import.txt
@@ -0,0 +1,5 @@
+// Map 009-2-5: Reid's Inn First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-5/_warps.txt",
+"npc/009-2-5/lovers.txt",
+"npc/009-2-5/savaric.txt",
diff --git a/npc/009-2-5/_warps.txt b/npc/009-2-5/_warps.txt
new file mode 100644
index 00000000..034d33b3
--- /dev/null
+++ b/npc/009-2-5/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-5: Reid's Inn First Floor warps
+009-2-5,56,32,0 warp #009-2-5_56_32 1,0,009-2-3,56,29
diff --git a/npc/009-2-5/lovers.txt b/npc/009-2-5/lovers.txt
new file mode 100644
index 00000000..463742b9
--- /dev/null
+++ b/npc/009-2-5/lovers.txt
@@ -0,0 +1,29 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Useless NPC. Possibly it is a memory fragment of Savaric and Reid?
+// THIS IS A PLACEHOLDER!
+
+009-2-5,27,27,0 script Lovers NPC_LOVERS,{
+ mesc l("You see a man and a woman holding each other very tight.");
+ next;
+ mesc l("They are kissing and whispering things to each other you can't hear.");
+ next;
+ mesc l("Now the woman giggles. They don't notice you.");
+ next;
+ select
+ l("Maybe it's better not to bother them."),
+ l("*ahem* Hello...?");
+ mes "";
+ if (@menu == 1)
+ close;
+ mesc l("They do not hear you. It is as if they were not real.");
+ next;
+ mesc l("This is certainly a strange place.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-5/savaric.txt b/npc/009-2-5/savaric.txt
new file mode 100644
index 00000000..dc1f08ab
--- /dev/null
+++ b/npc/009-2-5/savaric.txt
@@ -0,0 +1,20 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Savaric had an affair with Reid and ultimately brought death to the whole Inn.
+// THIS IS A PLACEHOLDER!
+
+009-2-5,31,41,0 script Savaric NPC_SAVARIC,{
+ mesc l("You see a dead man hanging. This place is creepy!");
+ next;
+ mesc l("Suddenly the man opens his eyes and looks at you.");
+ next;
+ mesn l("Hanged Man");
+ mesq l("Oh, hello. Nice to see you - I seem to be dead, but I don't know why and why I'm still consciousness. This is very interesting.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-6/_import.txt b/npc/009-2-6/_import.txt
new file mode 100644
index 00000000..f9cec10c
--- /dev/null
+++ b/npc/009-2-6/_import.txt
@@ -0,0 +1,5 @@
+// Map 009-2-6: Small House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-6/_warps.txt",
+"npc/009-2-6/eurni.txt",
+"npc/009-2-6/jpmorbid.txt",
diff --git a/npc/009-2-6/_warps.txt b/npc/009-2-6/_warps.txt
new file mode 100644
index 00000000..bfd06300
--- /dev/null
+++ b/npc/009-2-6/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-6: Small House warps
+009-2-6,29,36,0 warp #009-2-6_29_36 0,0,009-1,67,160
diff --git a/npc/009-2-6/eurni.txt b/npc/009-2-6/eurni.txt
new file mode 100644
index 00000000..44bbf953
--- /dev/null
+++ b/npc/009-2-6/eurni.txt
@@ -0,0 +1,22 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Eurni the Surgeon
+
+009-2-6,32,30,0 script Eurni NPC_EURNI,{
+ mesn;
+ mesq l("Are you tired of who you are?");
+ next;
+ mesn;
+ mesq l("Would you be interested in changing your... appearance?");
+ next;
+ Barber(false);
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/009-2-6/jpmorbid.txt b/npc/009-2-6/jpmorbid.txt
new file mode 100644
index 00000000..83d4c3c2
--- /dev/null
+++ b/npc/009-2-6/jpmorbid.txt
@@ -0,0 +1,61 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// J.P.Morbid the Asphodel Moors storage guy.
+
+009-2-6,27,30,0 script J.P. Morbid NPC_JPMORBID,{
+ // Storage/Banking function not unlocked in Artis
+ if (!getq(ArtisQuests_Lloyd)) {
+ speech
+ l("Oh hey!"),
+ l("I was supposed to act as storagekeeper, but I forgot my key."),
+ l("Come back later, perhaps I can find it.");
+ close;
+ }
+ mesn;
+ mesq l("Welcome to %s's Bank!", l($@BANK_TOWN$[.bankid]));
+ next;
+
+ do
+ {
+ select
+ l("I would like to store some items."),
+ l("I would like to perform money transactions."),
+ l("Is there any request for me?"),
+ menuaction(l("Quit"));
+
+ mes "";
+
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("Sure thing! I'll have your items transported here from Artis before you realize!");
+ next;
+ closeclientdialog();
+ openstorage();
+ close;
+ case 2:
+ MerchantGuild_Bank();
+ break;
+ case 3:
+ MerchantGuild_Quests(.bankid);
+ break;
+ default:
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ } while (true);
+ close;
+
+OnInit:
+ .distance = 4;
+
+ // Bank configuration
+ array_push($@BANK_NAME$, .name$);
+ array_push($@BANK_TOWN$, "Asphodel Moors");
+ .bankid = getarraysize($@BANK_NAME$)-1;
+ end;
+}
diff --git a/npc/009-2-7/_import.txt b/npc/009-2-7/_import.txt
new file mode 100644
index 00000000..5460b7d6
--- /dev/null
+++ b/npc/009-2-7/_import.txt
@@ -0,0 +1,5 @@
+// Map 009-2-7: Shop
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-7/_warps.txt",
+"npc/009-2-7/leofwin.txt",
+"npc/009-2-7/umfrey.txt",
diff --git a/npc/009-2-7/_warps.txt b/npc/009-2-7/_warps.txt
new file mode 100644
index 00000000..f675c6c2
--- /dev/null
+++ b/npc/009-2-7/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-7: Shop warps
+009-2-7,29,36,0 warp #009-2-7_29_36 0,0,009-1,64,187
diff --git a/npc/009-2-7/leofwin.txt b/npc/009-2-7/leofwin.txt
new file mode 100644
index 00000000..c634b9fb
--- /dev/null
+++ b/npc/009-2-7/leofwin.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Leofwin is now the status reset NPC
+// THIS IS A PLACEHOLDER!
+
+009-2-7,36,30,0 script Leofwin NPC_LEOFWIN,{
+ speech
+ l("Do you want a Status Reset?");
+
+ ConfirmStatusReset();
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-7/umfrey.txt b/npc/009-2-7/umfrey.txt
new file mode 100644
index 00000000..5463f7e2
--- /dev/null
+++ b/npc/009-2-7/umfrey.txt
@@ -0,0 +1,25 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Umfrey is the general shopkeeper of Asphodel Moors
+// THIS IS A PLACEHOLDER!
+
+009-2-7,44,30,0 script Umfrey NPC_UMFREY,{
+ closeclientdialog;
+ shop .name$;
+ close;
+
+OnInit:
+ .distance = 4;
+ tradertype(NST_MARKET);
+
+ sellitem TrainingArrow, -1, 20000;
+ sellitem DeathPotion, -1, 1;
+ end;
+
+OnClock0009:
+ restoreshopitem TrainingArrow, 20000;
+ restoreshopitem DeathPotion, 1;
+ end;
+}
diff --git a/npc/009-2-8/_import.txt b/npc/009-2-8/_import.txt
new file mode 100644
index 00000000..8488166f
--- /dev/null
+++ b/npc/009-2-8/_import.txt
@@ -0,0 +1,4 @@
+// Map 009-2-8: Blacksmith
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-8/_warps.txt",
+"npc/009-2-8/cerhan.txt",
diff --git a/npc/009-2-8/_warps.txt b/npc/009-2-8/_warps.txt
new file mode 100644
index 00000000..018f381b
--- /dev/null
+++ b/npc/009-2-8/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-8: Blacksmith warps
+009-2-8,29,41,0 warp #009-2-8_29_41 0,0,009-1,90,160
diff --git a/npc/009-2-8/cerhan.txt b/npc/009-2-8/cerhan.txt
new file mode 100644
index 00000000..927ba2a8
--- /dev/null
+++ b/npc/009-2-8/cerhan.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Cerhan is the armory guy from Asphodel Moors.
+// Relation with Ms. Golbenez is unknown?
+// THIS IS A PLACEHOLDER!
+
+009-2-8,39,30,0 script Cerhan NPC_CHELIOS,{
+ speech
+ l("Ah, hello! It's good to see another normal %s at this strange place!", get_race(GETRACE_RACE)),
+ l("I'm an experienced weapon master and I was thinking about establishing a smithy here. I'll need some more equipment, though."),
+ l("So, I'll talk to you later!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/009-2-9/_import.txt b/npc/009-2-9/_import.txt
new file mode 100644
index 00000000..cef8231a
--- /dev/null
+++ b/npc/009-2-9/_import.txt
@@ -0,0 +1,3 @@
+// Map 009-2-9: Migglemire Crypt Ground Level
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/009-2-9/_warps.txt",
diff --git a/npc/009-2-9/_warps.txt b/npc/009-2-9/_warps.txt
new file mode 100644
index 00000000..15eaa9e9
--- /dev/null
+++ b/npc/009-2-9/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 009-2-9: Migglemire Crypt Ground Level warps
+009-2-9,35,44,0 warp #009-2-9_35_44 1,0,009-1,195,97
+009-2-9,41,41,0 warp #009-2-9_41_41 1,0,009-2-10,41,34
diff --git a/npc/012-1/_import.txt b/npc/012-1/_import.txt
new file mode 100644
index 00000000..118dc1b3
--- /dev/null
+++ b/npc/012-1/_import.txt
@@ -0,0 +1,18 @@
+// Map 012-1: Candor Island
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-1/_mobs.txt",
+"npc/012-1/_warps.txt",
+"npc/012-1/aahna.txt",
+"npc/012-1/aidan.txt",
+"npc/012-1/ayasha.txt",
+"npc/012-1/crasmande.txt",
+"npc/012-1/hasan.txt",
+"npc/012-1/ishi.txt",
+"npc/012-1/kaan.txt",
+"npc/012-1/liana.txt",
+"npc/012-1/marine.txt",
+"npc/012-1/prawors.txt",
+"npc/012-1/tiki.txt",
+"npc/012-1/vincent.txt",
+"npc/012-1/wateranimation.txt",
+"npc/012-1/zegas.txt",
diff --git a/npc/012-1/_mobs.txt b/npc/012-1/_mobs.txt
new file mode 100644
index 00000000..ce3a3234
--- /dev/null
+++ b/npc/012-1/_mobs.txt
@@ -0,0 +1,12 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-1: Candor Island mobs
+012-1,77,78,30,25 monster Mana Bug 1035,8,10000,10000
+012-1,62,95,19,15 monster Butterfly 1032,5,100000,10000
+012-1,78,103,38,12 monster Maggot 1026,10,500,10000
+012-1,57,57,20,14 monster Grass Snake 1042,5,3000,12000
+012-1,106,42,16,7 monster Scorpion 1043,4,15000,50000
+012-1,115,123,14,7 monster Scorpion 1043,4,15000,40000
+012-1,91,81,10,15 monster Small Frog 1086,4,3000,30000
+012-1,86,86,7,11 monster Big Frog 1087,2,6000,75000
+012-1,103,55,14,13 monster Spiky Mushroom 1049,2,3000,6000
+012-1,43,51,3,4 monster Wicked Mushroom 1050,1,6000,12000
diff --git a/npc/012-1/_warps.txt b/npc/012-1/_warps.txt
new file mode 100644
index 00000000..e7f8b126
--- /dev/null
+++ b/npc/012-1/_warps.txt
@@ -0,0 +1,9 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-1: Candor Island warps
+012-1,38,115,0 warp #012-1_38_115 0,0,012-2-1,52,38
+012-1,50,104,0 warp #012-1_50_104 0,0,012-2-6,26,38
+012-1,65,105,0 warp #012-1_65_105 0,0,012-2-5,29,43
+012-1,64,95,0 warp #012-1_64_95 0,0,012-2-3,33,36
+012-1,51,93,0 warp #012-1_51_93 0,0,012-2-7,30,34
+012-1,57,101,0 warp #012-1_57_101 0,0,012-2-4,31,43
+012-1,49,67,0 warp #012-1_49_67 1,0,012-3-1,37,40
diff --git a/npc/012-1/aahna.txt b/npc/012-1/aahna.txt
new file mode 100644
index 00000000..39ad8192
--- /dev/null
+++ b/npc/012-1/aahna.txt
@@ -0,0 +1,17 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Aahna, a low quality NPC ;)
+// TODO: Ask for random drops from Mana Bugs (daily quest)
+
+012-1,99,64,0 script Aahna NPC_AAHNA,{
+ speech
+ l("Welcome."),
+ l("I am looking at Mana Bugs. They always drop a bug leg, it is weird.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/aidan.txt b/npc/012-1/aidan.txt
new file mode 100644
index 00000000..06776be3
--- /dev/null
+++ b/npc/012-1/aidan.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Aidan, a dawdler in Candor.
+// THIS IS A PLACEHOLDER!
+
+012-1,52,114,0 script Aidan NPC_AIDAN,{
+ speech
+ l("Welcome. I am Aidan, from the Monster Hunting Association."),
+ l("We host daily and weekly monster hunting objectives to adventurers based on their level."),
+ l("We aren't open yet because Ishi still can't decide how she will hand out the rewards."),
+ l("But once we open, remember to come to me to sign in our tasks and also to claim rewards with Ishi before they expire!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/ayasha.txt b/npc/012-1/ayasha.txt
new file mode 100644
index 00000000..ae47556a
--- /dev/null
+++ b/npc/012-1/ayasha.txt
@@ -0,0 +1,17 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Vincent, a child at the Candor beach.
+// THIS IS A PLACEHOLDER!
+
+012-1,65,111,0 script Ayasha NPC_AYASHA,{
+ speech
+ l("Hey adventurer!"),
+ l("I lost Liana, she was taking care of me; Have you seen her around? %%i");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/crasmande.txt b/npc/012-1/crasmande.txt
new file mode 100644
index 00000000..85d9308e
--- /dev/null
+++ b/npc/012-1/crasmande.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Crasmande, the scared man.
+// THIS IS A PLACEHOLDER!
+
+012-1,41,44,0 script Crasmande NPC_CRASMANDE,{
+ speech
+ l("I'm scared!"),
+ l("Hasan is bullying me!"),
+ l("%%i");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/hasan.txt b/npc/012-1/hasan.txt
new file mode 100644
index 00000000..79cf9023
--- /dev/null
+++ b/npc/012-1/hasan.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Hasan, the bad guy.
+// THIS IS A PLACEHOLDER!
+
+012-1,39,44,0 script Hasan NPC_HASAN,{
+ speech
+ l("Hey. I did nothing, I swear."),
+ l("Crasmande has been this way since I got here."),
+ l("Don't you have more important business to attend to, anyway?");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/ishi.txt b/npc/012-1/ishi.txt
new file mode 100644
index 00000000..a7322978
--- /dev/null
+++ b/npc/012-1/ishi.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Ishi, former trade-in for monster points.
+// THIS IS A PLACEHOLDER!
+
+012-1,53,114,0 script Ishi NPC_ISHI,{
+ speech
+ l("Welcome. I am Ishi, from the Monster Hunting Association."),
+ l("I only follow Aidan around, so make your questions to him instead.");
+ next;
+ mesn;
+ mesc l("Ishi seems to be very pensative of something, it is better if we don't disturb her.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/kaan.txt b/npc/012-1/kaan.txt
new file mode 100644
index 00000000..2ea7ad2a
--- /dev/null
+++ b/npc/012-1/kaan.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Kaan, a guy good for nothing.
+// THIS IS A PLACEHOLDER!
+
+012-1,53,110,0 script Kaan NPC_KAAN,{
+ speech
+ l("Welcome to Candor!"),
+ l("Such a bright shine day! I would love to tell you stories about this town."),
+ l("But not now, I'm in the mood to stay under the sun for a while longer."),
+ l("I hope Tanisha is not slacking off. I would hate having to go check on her.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/liana.txt b/npc/012-1/liana.txt
new file mode 100644
index 00000000..ac2ceb9b
--- /dev/null
+++ b/npc/012-1/liana.txt
@@ -0,0 +1,25 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Liana.
+// THIS IS A PLACEHOLDER!
+
+012-1,65,117,0 script Liana NPC_LIANA,{
+ mesn;
+ mesc l("*sighs*");
+ next;
+ mesn;
+ mesq l("Ayasha went to explore the caves in Candor. They said there was a pretty tree there.");
+ next;
+ mesn;
+ mesq l("...But then she saw the spiders and got scared.");
+ next;
+ mesn;
+ mesq l("Now she is crying looking for me. The poor kid.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/marine.txt b/npc/012-1/marine.txt
new file mode 100644
index 00000000..db261fd0
--- /dev/null
+++ b/npc/012-1/marine.txt
@@ -0,0 +1,17 @@
+// Moubootaur Legends scripts.
+// Authors:
+// Jesusalva
+// Description:
+// This script controls access to Ships, fixing variables.
+
+// Use NPC_LA_MARINE if needed
+012-1,64,133,0 script La Marine#C NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ EnterTown("Candor");
+
+ warp "marine@"+LOCATION$, 42, 26;
+ closedialog;
+ close;
+}
diff --git a/npc/012-1/prawors.txt b/npc/012-1/prawors.txt
new file mode 100644
index 00000000..8acf73a1
--- /dev/null
+++ b/npc/012-1/prawors.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Prawors, the captain in Candor.
+// THIS IS A PLACEHOLDER!
+
+012-1,53,122,0 script Prawors NPC_PRAWORS,{
+ speech
+ l("Arrhoy!"),
+ l("Saluc Golden Beard, the greediest of all ship captains, charges money for trips. so if you don't have money to pay him, you're stranded here FOREVER!"),
+ l("I hope you enjoy this town! Meanwhile, I wonder where I put my %s...", getitemlink(TreasureMap));
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/tiki.txt b/npc/012-1/tiki.txt
new file mode 100644
index 00000000..5596c2ad
--- /dev/null
+++ b/npc/012-1/tiki.txt
@@ -0,0 +1,150 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Tiki is the sandwich maker of Candor
+
+012-1,116,118,0 script Tiki NPC_TIKI,{
+ function tikiSubmit;
+ function tikiMenu;
+ function tikiShop;
+ mesn;
+ mesq l("Hey there, shady fella. Whaddaya want in Candor shores?");
+ next;
+ if (getq(General_Cooking) == 7)
+ tikiMenu();
+ if (getq(General_Cooking) == 8)
+ tikiSubmit();
+ tikiShop();
+ end;
+
+function tikiShop {
+ closeclientdialog;
+ shop .name$;
+ return;
+}
+
+function tikiMenu {
+ .@q2=getq2(General_Cooking);
+ select
+ l("Just wanted to purchase ingredients for cooking."),
+ l("Actually, I would like to learn some recipes."),
+ l("Actually I'm lost. Sorry.");
+ mes "";
+ // Explode script as requested
+ if (@menu == 3)
+ close;
+ // Return so shop can take over
+ if (@menu == 1)
+ return;
+ // @menu == 2, "I would like to learn some recipes"
+ mesn strcharinfo(0);
+ mesc l("You quickly explain the situation and request the %s sandwich.", getitemlink(.@q2 == VEGAN ? MananaSandwich : PioulegSandwich));
+ next;
+ mesn;
+ mesq l("Ahh, I see! Very shady indeed, almost as shady as you are!");
+ next;
+ mesn;
+ mesq l("I would like to help, but I can't. I'm busy, you see! Candor's Sandwich Making Contest is coming up, and I never lost a single instance of it!");
+ next;
+ select
+ l("Ah, too bad, I'll ask Yannika for more ideas, bye."),
+ l("How come you never lost before?"),
+ l("Perhaps I can help?");
+ mes "";
+ if (@menu == 1)
+ close;
+ if (@menu == 2) {
+ mesn;
+ mesq l("Because I'm so great! I am so good, that the other challengers doesn't even show up in fear of losing to me!");
+ next;
+ mesn;
+ mesq l("Anyway, perhaps you could help me, and I'll help you in exchange. Whaddaya think?");
+ next;
+ }
+ mesn;
+ mesq l("It is really easy - I need an idea. Bring me something NEW, revolutionary, to make a sandwich out of it. And I'll teach you the recipe!");
+ next;
+ setq1 General_Cooking, 8;
+ return;
+}
+
+function tikiSubmit {
+ mesc "[" + .name$ + "]";
+ mesc l("\"Bring me something NEW, revolutionary, to make a sandwich out of it.\"");
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+
+ .@id = requestitem();
+
+ // If ID is invalid
+ if (.@id < 1)
+ close;
+
+ // If there's not enough items, it is bound, it cannot be traded/dropped/sold, etc.
+ // TODO: Prevent plates/bowls from being destroyed this way!!
+ if (countitem(.@id) < 1 || checkbound(.@id) || getiteminfo(.@id, ITEMINFO_TYPE) != IT_HEALING) {
+ mesc l("This item cannot be given.");
+ close;
+ }
+
+ mesc l("Are you sure you want to give %s to %s? Item will be lost!",
+ getitemlink(.@id), .name$), 1;
+ if (askyesno() == ASK_NO)
+ close;
+
+ mesn;
+ mesq l("%s puts %s on between two bread slices and try it.", .name$, getitemname(.@id));
+ next;
+ delitem .@id, 1;
+ if (.@id != MoubooSteak) {
+ mesn;
+ mesc l("%s starts shouting insults at you!", .name$);
+ next;
+ mesn;
+ mesq l("This is the worst. sandwich. ever! How do you dare to give me such thing?!");
+ next;
+ mesn;
+ mesq l("Go get me something else, go do it NOW!!");
+ mesc l("...Maybe if he put the cheese and lettuce as you usually do, it would have tasted great... *sigh*");
+ close;
+ }
+ setq1 General_Cooking, 9;
+ setq1 General_SmearedHands, 3;
+ RECIPES[(.@q2 == VEGAN ? CraftMananaSandwich : CraftPioulegSandwich)]=true;
+ mesn;
+ mesq l("Uh - Oh. This is... Actually good!");
+ next;
+ mesn;
+ mesq l("I'm sure I'll win this year's contest as well! Hah, just wait and see!");
+ next;
+ mesn;
+ mesq l("What? Still want that shady recipe? Meh, just cut a bread, throw in three lettuce leaves, two cheese, and put the special ingredient - A %s!", getitemname(.@q2 == VEGAN ? Manana : PiouLegs));
+ next;
+ mesq l("And vói-la, you have your sandwich done. Now go, I have a contest to win! Hahaha!");
+ close;
+}
+
+OnInit:
+ .distance = 4;
+ tradertype(NST_MARKET);
+
+ sellitem Bread, -1, 35;
+ sellitem PiouLegs, -1, 25;
+ sellitem Manana, -1, 20;
+ sellitem Cheese, -1, 12;
+ sellitem LettuceLeaf, -1, 10;
+ sellitem CommonCarp, -1, 8;
+ sellitem GrassCarp, -1, 7;
+ end;
+
+OnClock0001:
+ restoreshopitem Bread, 35;
+ restoreshopitem PiouLegs, 25;
+ restoreshopitem Manana, 20;
+ restoreshopitem Cheese, 12;
+ restoreshopitem LettuceLeaf, 10;
+ restoreshopitem CommonCarp, 8;
+ restoreshopitem GrassCarp, 7;
+ end;
+}
+
diff --git a/npc/012-1/vincent.txt b/npc/012-1/vincent.txt
new file mode 100644
index 00000000..e859d02e
--- /dev/null
+++ b/npc/012-1/vincent.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Vincent, a child at the Candor beach.
+// THIS IS A PLACEHOLDER!
+
+012-1,121,126,0 script Vincent NPC_VINCENT,{
+ speech
+ l("Scorpions everywhere!"),
+ l("Why do they show up, anyway? I thought Scorpions prefered deserts, not beaches."),
+ l("I need to study more... But... I want to play! And I want to make figurines!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-1/wateranimation.txt b/npc/012-1/wateranimation.txt
new file mode 100644
index 00000000..ad1b41e4
--- /dev/null
+++ b/npc/012-1/wateranimation.txt
@@ -0,0 +1,12 @@
+// The Mana World scripts.
+// Description:
+// Water animations, splash, fishes, etc...
+
+012-1,87,92,0 duplicate(#fish_river2) #candor_fish01 NPC_WATER_SPLASH
+012-1,86,85,0 duplicate(#fish_river2) #candor_fish02 NPC_WATER_SPLASH
+012-1,98,74,0 duplicate(#fish_river2) #candor_fish03 NPC_WATER_SPLASH
+012-1,94,76,0 duplicate(#fish_river2) #candor_fish04 NPC_WATER_SPLASH
+012-1,61,73,0 duplicate(#fish_river2) #candor_fish05 NPC_WATER_SPLASH
+012-1,65,74,0 duplicate(#fish_river2) #candor_fish06 NPC_WATER_SPLASH
+012-1,58,64,0 duplicate(#fish_river2) #candor_fish07 NPC_WATER_SPLASH
+
diff --git a/npc/012-1/zegas.txt b/npc/012-1/zegas.txt
new file mode 100644
index 00000000..29f72a5d
--- /dev/null
+++ b/npc/012-1/zegas.txt
@@ -0,0 +1,36 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Zegas, the guy who want you to clean storage room.
+// THIS IS A PLACEHOLDER!
+
+012-1,48,105,0 script Zegas NPC_ZEGAS,{
+ mesn;
+ mesc l("*sighs*");
+ next;
+ mesn;
+ mesq l("I need someone to clean the storage room...");
+ next;
+ mesn;
+ mesq l("Hey, you! Don't you want to clean the storage room for me?");
+ next;
+ select
+ l("Yes, of course!"),
+ l("'course not!");
+ mes "";
+ mesn;
+ if (@menu == 2) {
+ mesq l("Nobody ever does...");
+ } else {
+ mesc l("Zegas hands you a broom.");
+ mesq l("Good, now start cleaning it!");
+ // TODO: Maybe we actually could have you cleaning the room boxes.
+ // Then you find a peculiar dusty utensil inside. Then, some quest begins.
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-2-1/_import.txt b/npc/012-2-1/_import.txt
new file mode 100644
index 00000000..13ff23d2
--- /dev/null
+++ b/npc/012-2-1/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-2-1: Sorfina's Home
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-1/_warps.txt",
+"npc/012-2-1/jessie.txt",
+"npc/012-2-1/tanisha.txt",
diff --git a/npc/012-2-1/_warps.txt b/npc/012-2-1/_warps.txt
new file mode 100644
index 00000000..4ccc3898
--- /dev/null
+++ b/npc/012-2-1/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-1: Sorfina's Home warps
+012-2-1,52,39,0 warp #012-2-1_52_39 0,0,012-1,38,116
+012-2-1,53,30,0 warp #012-2-1_53_30 0,0,012-2-2,30,34
diff --git a/npc/012-2-1/jessie.txt b/npc/012-2-1/jessie.txt
new file mode 100644
index 00000000..7356bfe6
--- /dev/null
+++ b/npc/012-2-1/jessie.txt
@@ -0,0 +1,30 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Jessie, Sorfina's old husband.
+// THIS IS A PLACEHOLDER!
+
+012-2-1,38,30,0 script Jessie NPC_JESSIE,{
+ speech
+ l("Welcome."),
+ l("I am \"uncle\" Jessie and I teach the kids in Candor.");
+ next;
+ mesn;
+ mesq l("Actually... Do you know why the Piou crossed the road?");
+ next;
+ if (askyesno() == ASK_NO) {
+ mesn;
+ mesq l("Dang! I don't know either, but I'm too shy to ask.");
+ } else {
+ mesc l("Why the Piou crossed the road?");
+ input .@jessanswer$;
+ mesn;
+ mesq l("Pfft, you obviously don't know either!");
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-2-1/tanisha.txt b/npc/012-2-1/tanisha.txt
new file mode 100644
index 00000000..a0bb358b
--- /dev/null
+++ b/npc/012-2-1/tanisha.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Tanisha, the little girl in Sorfina's house.
+// THIS IS A PLACEHOLDER!
+
+012-2-1,48,34,0 script Tanisha NPC_TANISHA,{
+ speech
+ l("Welcome."),
+ l("Kaan asked me to kill maggots, which I hate! But I'm not seeing any..."),
+ l("I wonder if things were supposed to be this way?");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-2-2/_import.txt b/npc/012-2-2/_import.txt
new file mode 100644
index 00000000..3990e3db
--- /dev/null
+++ b/npc/012-2-2/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-2-2: Sleeping Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-2/_savepoints.txt",
+"npc/012-2-2/_warps.txt",
+"npc/012-2-2/sorfina.txt",
diff --git a/npc/012-2-2/_savepoints.txt b/npc/012-2-2/_savepoints.txt
new file mode 100644
index 00000000..1aedace4
--- /dev/null
+++ b/npc/012-2-2/_savepoints.txt
@@ -0,0 +1,28 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-2: Sleeping Room saves
+012-2-2,25,27,0 script #save_012-2-2_25_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
+012-2-2,28,27,0 script #save_012-2-2_28_27 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/012-2-2/_warps.txt b/npc/012-2-2/_warps.txt
new file mode 100644
index 00000000..f174dc7c
--- /dev/null
+++ b/npc/012-2-2/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-2: Sleeping Room warps
+012-2-2,30,35,0 warp #012-2-2_30_35 0,0,012-2-1,53,31
diff --git a/npc/012-2-2/sorfina.txt b/npc/012-2-2/sorfina.txt
new file mode 100644
index 00000000..4c8f476e
--- /dev/null
+++ b/npc/012-2-2/sorfina.txt
@@ -0,0 +1,34 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Sorfina, the former starting NPC. Could need a new job.
+// THIS IS A PLACEHOLDER!
+
+012-2-2,26,30,0 script Sorfina NPC_SORFINA,{
+ speech
+ l("Welcome, adventurer."),
+ l("I will never know why people barge in others' houses and get away with it."),
+ l("Ah, no, I'm not telling you to go away. Visits are always welcome, it gets lonely over time. But I don't have anything to offer you otherwise.");
+ if (islegacyaccount() && countitem(ClothesPack)) goto L_Legacy;
+ close;
+
+L_Legacy:
+ next;
+ mesn;
+ mesq l("Actually, I see you have some really torn %s.", getitemlink(ClothesPack));
+ next;
+ mesn;
+ mesq l("I see things from several kinds on it - from iron, to steel, to bone, rock, leather, cotton, cashmere, and many others.");
+ next;
+ mesn;
+ mesq l("I wonder what sort of sea disaster could have destroyed them so badly. But, I believe they can be repaired with magic.");
+ next;
+ mesn;
+ mesq l("If only the developers - my next door neighbor - weren't so lazy, maybe I would be able to repair them or know someone able to do that. Sorry.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-2-3/_import.txt b/npc/012-2-3/_import.txt
new file mode 100644
index 00000000..e04ba715
--- /dev/null
+++ b/npc/012-2-3/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-2-3: Candor Shop
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-3/_warps.txt",
+"npc/012-2-3/cynric.txt",
+"npc/012-2-3/nyle.txt",
diff --git a/npc/012-2-3/_warps.txt b/npc/012-2-3/_warps.txt
new file mode 100644
index 00000000..a64e4ecb
--- /dev/null
+++ b/npc/012-2-3/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-3: Candor Shop warps
+012-2-3,33,37,0 warp #012-2-3_33_37 0,0,012-1,64,96
diff --git a/npc/012-2-3/cynric.txt b/npc/012-2-3/cynric.txt
new file mode 100644
index 00000000..712e4270
--- /dev/null
+++ b/npc/012-2-3/cynric.txt
@@ -0,0 +1,54 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Cynric, Candor's banker.
+// THIS IS A PLACEHOLDER!
+
+012-2-3,27,28,0 script Cynric NPC_CYNRIC,{
+ mesn;
+ mesq l("Welcome to %s's Bank!", l($@BANK_TOWN$[.bankid]));
+ next;
+
+ do
+ {
+ select
+ l("I would like to store some items."),
+ l("I would like to perform money transactions."),
+ l("Is there any request for me?"),
+ menuaction(l("Quit"));
+
+ mes "";
+
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("Sure thing! I'll have your items transported here from Artis before you realize!");
+ next;
+ closeclientdialog();
+ openstorage();
+ close;
+ case 2:
+ MerchantGuild_Bank();
+ break;
+ case 3:
+ MerchantGuild_Quests(.bankid);
+ break;
+ default:
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ } while (true);
+ close;
+
+OnInit:
+ .distance = 4;
+
+ // Bank configuration
+ array_push($@BANK_NAME$, .name$);
+ array_push($@BANK_TOWN$, "Candor");
+ .bankid = getarraysize($@BANK_NAME$)-1;
+ end;
+}
diff --git a/npc/012-2-3/nyle.txt b/npc/012-2-3/nyle.txt
new file mode 100644
index 00000000..900f8776
--- /dev/null
+++ b/npc/012-2-3/nyle.txt
@@ -0,0 +1,67 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Nyle, Candor's shopkeeper.
+// THIS IS A PLACEHOLDER!
+
+012-2-3,42,30,0 script Nyle NPC_NYLE,{
+ mesn;
+ mesq l("Welcome to my fine shop.");
+ next;
+ closeclientdialog;
+ shop .name$;
+ close;
+
+OnInit:
+ .distance = 4;
+ tradertype(NST_MARKET);
+
+ // Equips
+ sellitem BrimmedHat, -1, 35;
+ sellitem Armbands, -1, 20;
+ sellitem IronArmbands, -1, 20;
+ sellitem BrownTrousers, -1, 30;
+ sellitem LousyMoccasins, -1, 20;
+ sellitem WoodenSword, -1, 50;
+ sellitem PiouSlayer, -1, 15;
+ sellitem LeatherShield, -1, 30;
+ sellitem TrainingArrow, -1, 20000;
+
+ // Edible
+ sellitem Bread, -1, 15;
+ sellitem CommonCarp, -1, 8;
+ sellitem GrassCarp, -1, 7;
+ sellitem PiberriesInfusion, -1, 200;
+ sellitem FatesPotion, -1, 100;
+ sellitem ClothoLiquor, -1, 50;
+ sellitem LachesisBrew, -1, 30;
+ sellitem AtroposMixture, -1, 10;
+ sellitem ElixirOfLife, -1, 2;
+
+ // Misc
+ sellitem PiouEgg, -1, 25;
+ end;
+
+OnClock0001:
+ restoreshopitem BrimmedHat, 35;
+ restoreshopitem Armbands, 20;
+ restoreshopitem IronArmbands, 20;
+ restoreshopitem BrownTrousers, 30;
+ restoreshopitem LousyMoccasins, 20;
+ restoreshopitem WoodenSword, 50;
+ restoreshopitem PiouSlayer, 15;
+ restoreshopitem LeatherShield, 30;
+ restoreshopitem TrainingArrow, 20000;
+ restoreshopitem Bread, 15;
+ restoreshopitem CommonCarp, 8;
+ restoreshopitem GrassCarp, 7;
+ restoreshopitem PiberriesInfusion, 200;
+ restoreshopitem FatesPotion, 100;
+ restoreshopitem ClothoLiquor, 50;
+ restoreshopitem LachesisBrew, 30;
+ restoreshopitem AtroposMixture, 10;
+ restoreshopitem ElixirOfLife, 2;
+ restoreshopitem PiouEgg, 25;
+ end;
+}
diff --git a/npc/012-2-4/_import.txt b/npc/012-2-4/_import.txt
new file mode 100644
index 00000000..659fdc67
--- /dev/null
+++ b/npc/012-2-4/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-2-4: Alchemy Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-4/_warps.txt",
+"npc/012-2-4/morgan.txt",
+"npc/012-2-4/zitoni.txt",
diff --git a/npc/012-2-4/_warps.txt b/npc/012-2-4/_warps.txt
new file mode 100644
index 00000000..156a6e54
--- /dev/null
+++ b/npc/012-2-4/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-4: Alchemy Hut warps
+012-2-4,31,44,0 warp #012-2-4_31_44 0,0,012-1,57,102
diff --git a/npc/012-2-4/morgan.txt b/npc/012-2-4/morgan.txt
new file mode 100644
index 00000000..e044f509
--- /dev/null
+++ b/npc/012-2-4/morgan.txt
@@ -0,0 +1,22 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Rosen, the salesman in Candor smith.
+// THIS IS A PLACEHOLDER!
+
+012-2-4,26,37,0 script Morgan NPC_MORGAN,{
+ speech
+ l("Hello Wanderer."),
+ l("I am Morgan, the alchemist."),
+ l("(People do not like to hear the word 'witch' so much, as we live close to Hurnscald)."),
+ l("Unfortunately my apprentice Zitoni does not bring me fresh potions, so if you need something you should come back later."),
+ l("Unless you want a Status Reset?");
+
+ ConfirmStatusReset();
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-2-4/zitoni.txt b/npc/012-2-4/zitoni.txt
new file mode 100644
index 00000000..1d8ce355
--- /dev/null
+++ b/npc/012-2-4/zitoni.txt
@@ -0,0 +1,76 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Zitoni, Morgan's apprentice.
+// THIS IS A PLACEHOLDER!
+
+012-2-4,40,37,0 script Zitoni NPC_ZITONI,{
+
+OnTalk:
+ mesn "The man shivers";
+ mesq l("The world is so cruel! Oh, cruel world!");
+ next;
+
+ menu
+ l("I do not like whiners."), -,
+ l("What is your problem?"), L_toams;
+
+ close;
+
+L_toams:
+ mesn "He looks at you.";
+ mesq l("I would so much like to brew potions, but...");
+ next;
+ mesq l("I CANNOT WALK!");
+ next;
+ mesq l("Please, please try to find a guy named toams - he is capable to make me walk again! Please!");
+ next;
+
+ menu
+ l("Ok, I can try."), -,
+ l("Ok, but do you have something else?"), L_jez;
+
+ close;
+
+L_jez:
+ mesq l("Oh, yes! So kind that you ask");
+ next;
+ mesq l("I forgot my tasks to do!");
+ next;
+ mesq l("If only I remembered what I was supposed to do!");
+ next;
+ mesq l("Please, can you look for a guy named Jesusalva? I am very sure he remembers what kind of quest I was going to accomplish.");
+ next;
+
+ menu
+ l("Ok, I will do that, but now I must leave."), -,
+ l("Is that all, or do you have more problems?"), L_wildx;
+ close;
+
+L_wildx:
+ mesq l("Unfortunately yes.");
+ next;
+ mesq l("I totally forgot why I am here, and what I am doing here!");
+ next;
+ mesq l("Please, please find WildX. He will explain to me what my role in this world has been.");
+
+ menu
+ l("Ok, but all that will keep me busy for a while. So, goodbye."), -,
+ l("You do not have more problems, do you?"), L_mick;
+ close;
+
+L_mick:
+ mesq l("Sure I have one more problem.");
+ next;
+ mesq l("Did you ever look at me?!? That ugly robe, that weird whatever I hold in my hand, my strange face and all that!");
+ next;
+ mesq l("Can you do a last task for me and try to find Micksha? He sure can help me to look a bit less ugly.");
+ next;
+ mesq("That would be so helpful! Please return soon to tell me about your progress.");
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/012-2-5/_import.txt b/npc/012-2-5/_import.txt
new file mode 100644
index 00000000..1a36bb4d
--- /dev/null
+++ b/npc/012-2-5/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-2-5: Candor Smith
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-5/_warps.txt",
+"npc/012-2-5/rosen.txt",
+"npc/012-2-5/toichi.txt",
diff --git a/npc/012-2-5/_warps.txt b/npc/012-2-5/_warps.txt
new file mode 100644
index 00000000..d5a52d94
--- /dev/null
+++ b/npc/012-2-5/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-5: Candor Smith warps
+012-2-5,29,44,0 warp #012-2-5_29_44 0,0,012-1,65,106
diff --git a/npc/012-2-5/rosen.txt b/npc/012-2-5/rosen.txt
new file mode 100644
index 00000000..201d4053
--- /dev/null
+++ b/npc/012-2-5/rosen.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Rosen, the salesman in Candor smith.
+// THIS IS A PLACEHOLDER!
+
+012-2-5,31,34,0 script Rosen NPC_ROSEN,{
+ speech
+ l("Welcome."),
+ l("I am Rosen, I am selling the best weapons and armor you can get on this island."),
+ l("If only Toichi would work harder, I could even offer you something. But meh. Like things are, you must try to return at a later point."),
+ l("Toichi, go to work! Stop drinking beer!");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-2-5/toichi.txt b/npc/012-2-5/toichi.txt
new file mode 100644
index 00000000..6c35172e
--- /dev/null
+++ b/npc/012-2-5/toichi.txt
@@ -0,0 +1,73 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Toichi, the smith in Candor island.
+// THIS IS A PLACEHOLDER!
+
+012-2-5,40,35,0 script Toichi NPC_TOICHI,{
+ function askCrafting;
+ speech
+ l("Hi there."),
+ l("My name is Toichi, and it seems I am the only one working on this lazy island.");
+ next;
+ mesq l("So I kindly request you not to listen to that stupid Rosen, saying 'Toichi is lazy'.");
+ next;
+ mesq l("At least I am doing something!");
+ // TODO: Add here a check for crafting skills
+ askCrafting();
+ close;
+
+function askCrafting {
+ next;
+ select
+ l("Okay..."),
+ l("Hey, do you mind if I use your equipment?"),
+ rif(is_dev(), "[Debug]");
+ mes "";
+ if (@menu == 1)
+ return;
+
+ // Debug
+ if (debug && @menu == 3)
+ RECIPES[CraftInfantryHelmet]=!RECIPES[CraftInfantryHelmet];
+ if (debug || @menu == 3)
+ mesf("[DEBUG] Knows the infantry helmet recipe? %s",
+ (RECIPES[CraftInfantryHelmet] ? "YES" : "NO"));
+
+ mesn;
+ mesq l("Sure, go ahead. But I'll charge you %d E per craft as commission!", .price);
+ next;
+ do {
+ mesc l("What will you craft today?");
+ mesc l("It costs %d E to use.", .price), 1;
+ if (Zeny < .price)
+ close;
+
+ if (SmithSystem()) {
+ // This should NEVER, EVER happen.
+ if (Zeny < .price) {
+ mesc l("WARNING, you have been detected cheating and thus, violating Gasaron Anti-Theft Policy."), 1;
+ mesc l("You were jailed and now need a GM to get you out of there."), 1;
+ // At this point I just c/p the code
+ logmes "WARNING, "+strcharinfo(0)+" found out cheating, only had "+Zeny+" Esperins for craft table. Jailed.", LOGMES_ATCOMMAND;
+ atcommand("@jail "+strcharinfo(0));
+ Zeny=0;
+ close;
+ }
+ Zeny-=.price;
+ mesc l("Success!"), 3;
+ } else {
+ mesc l("That didn't work!"), 1;
+ }
+ next;
+ mesc l("Try again?");
+ } while (askyesno() == ASK_YES);
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ .price = 6000;
+ end;
+}
diff --git a/npc/012-2-6/_import.txt b/npc/012-2-6/_import.txt
new file mode 100644
index 00000000..e239ad17
--- /dev/null
+++ b/npc/012-2-6/_import.txt
@@ -0,0 +1,3 @@
+// Map 012-2-6: Storage Room
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-6/_warps.txt",
diff --git a/npc/012-2-6/_warps.txt b/npc/012-2-6/_warps.txt
new file mode 100644
index 00000000..a56767e0
--- /dev/null
+++ b/npc/012-2-6/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-6: Storage Room warps
+012-2-6,26,39,0 warp #012-2-6_26_39 0,0,012-1,50,105
diff --git a/npc/012-2-7/_import.txt b/npc/012-2-7/_import.txt
new file mode 100644
index 00000000..5224df90
--- /dev/null
+++ b/npc/012-2-7/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-2-7: Small House
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-2-7/_savepoints.txt",
+"npc/012-2-7/_warps.txt",
+"npc/012-2-7/marazor.txt",
diff --git a/npc/012-2-7/_savepoints.txt b/npc/012-2-7/_savepoints.txt
new file mode 100644
index 00000000..0230a227
--- /dev/null
+++ b/npc/012-2-7/_savepoints.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-7: Small House saves
+012-2-7,26,31,0 script #save_012-2-7_26_31 NPC_SAVE_POINT,0,0,{
+ savepointparticle .map$, .x, .y, NO_INN;
+ close;
+
+OnInit:
+ .distance = 2;
+ .sex = G_OTHER;
+ end;
+
+OnTouch:
+ bedTouch();
+ end;
+}
diff --git a/npc/012-2-7/_warps.txt b/npc/012-2-7/_warps.txt
new file mode 100644
index 00000000..29b5aab2
--- /dev/null
+++ b/npc/012-2-7/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-2-7: Small House warps
+012-2-7,30,35,0 warp #012-2-7_30_35 0,0,012-1,51,94
diff --git a/npc/012-2-7/marazor.txt b/npc/012-2-7/marazor.txt
new file mode 100644
index 00000000..9de84bf9
--- /dev/null
+++ b/npc/012-2-7/marazor.txt
@@ -0,0 +1,16 @@
+// The Mana World scripts.
+// Author:
+// Livio
+// Description:
+// Marazor the barber
+// THIS IS A PLACEHOLDER!
+
+012-2-7,33,29,0 script Marazor NPC_GUMI_THE_DYER,{
+ Barber(true);
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/012-3-1/_import.txt b/npc/012-3-1/_import.txt
new file mode 100644
index 00000000..8856cef8
--- /dev/null
+++ b/npc/012-3-1/_import.txt
@@ -0,0 +1,4 @@
+// Map 012-3-1: Cador Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-3-1/_mobs.txt",
+"npc/012-3-1/_warps.txt",
diff --git a/npc/012-3-1/_mobs.txt b/npc/012-3-1/_mobs.txt
new file mode 100644
index 00000000..60055f77
--- /dev/null
+++ b/npc/012-3-1/_mobs.txt
@@ -0,0 +1,8 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-1: Cador Cave mobs
+012-3-1,47,44,17,18 monster Spider 1044,5,4000,8000
+012-3-1,47,47,23,18 monster Cave Maggot 1027,8,2000,20000
+012-3-1,41,30,13,6 monster Green Slime 1024,3,20000,75000
+012-3-1,51,56,15,7 monster Black Scorpion 1104,1,4000,8000
+012-3-1,60,48,11,14 monster AngryCrafty 1103,3,50000,2500
+012-3-1,36,43,11,7 monster AngryCrafty 1103,2,50000,2500
diff --git a/npc/012-3-1/_warps.txt b/npc/012-3-1/_warps.txt
new file mode 100644
index 00000000..4de4ef4a
--- /dev/null
+++ b/npc/012-3-1/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-1: Cador Cave warps
+012-3-1,43,44,0 warp #012-3-1_43_44 1,0,012-3-3,44,97
+012-3-1,68,62,0 warp #012-3-1_68_62 0,2,012-3-2,22,45
+012-3-1,37,41,0 warp #012-3-1_37_41 2,0,012-1,48,68
diff --git a/npc/012-3-2/_import.txt b/npc/012-3-2/_import.txt
new file mode 100644
index 00000000..1aaa4813
--- /dev/null
+++ b/npc/012-3-2/_import.txt
@@ -0,0 +1,4 @@
+// Map 012-3-2: Candor Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-3-2/_mobs.txt",
+"npc/012-3-2/_warps.txt",
diff --git a/npc/012-3-2/_mobs.txt b/npc/012-3-2/_mobs.txt
new file mode 100644
index 00000000..ee085d8d
--- /dev/null
+++ b/npc/012-3-2/_mobs.txt
@@ -0,0 +1,8 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-2: Parua Cave mobs
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-2: Candor Cave mobs
+012-3-2,55,39,13,14 monster Spider 1044,5,4000,8000
+012-3-2,54,41,15,12 monster Black Scorpion 1104,4,4000,8000
+012-3-2,56,41,17,10 monster AngryCrafty 1103,3,50000,2500
+012-3-2,48,40,26,6 monster Cave Maggot 1027,6,2000,20000
diff --git a/npc/012-3-2/_warps.txt b/npc/012-3-2/_warps.txt
new file mode 100644
index 00000000..25b3477a
--- /dev/null
+++ b/npc/012-3-2/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-2: Parua Cave warps
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-2: Candor Cave warps
+012-3-2,21,46,0 warp #012-3-2_21_46 0,1,012-3-1,67,61
diff --git a/npc/012-3-3/_import.txt b/npc/012-3-3/_import.txt
new file mode 100644
index 00000000..ee48f7ee
--- /dev/null
+++ b/npc/012-3-3/_import.txt
@@ -0,0 +1,5 @@
+// Map 012-3-3: Mana Tree Cave
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/012-3-3/_mobs.txt",
+"npc/012-3-3/_warps.txt",
+"npc/012-3-3/manatree.txt",
diff --git a/npc/012-3-3/_mobs.txt b/npc/012-3-3/_mobs.txt
new file mode 100644
index 00000000..1d281763
--- /dev/null
+++ b/npc/012-3-3/_mobs.txt
@@ -0,0 +1,7 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-3: Mana Tree Cave mobs
+012-3-3,40,28,13,3 monster Green Slime 1024,4,20000,75000
+012-3-3,41,53,15,31 monster Crafty 1018,7,2500,35000
+012-3-3,36,35,9,7 monster Mana Bug 1035,5,10000,10000
+012-3-3,42,39,8,12 monster Silkworm 1040,5,3000,6000
+012-3-3,42,35,7,6 monster Moubi 1072,1,500000,1000000
diff --git a/npc/012-3-3/_warps.txt b/npc/012-3-3/_warps.txt
new file mode 100644
index 00000000..c0e6bf40
--- /dev/null
+++ b/npc/012-3-3/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 012-3-3: Mana Tree Cave warps
+012-3-3,44,98,0 warp #012-3-3_44_98 0,0,012-3-1,42,45
diff --git a/npc/012-3-3/manatree.txt b/npc/012-3-3/manatree.txt
new file mode 100644
index 00000000..7f37ad30
--- /dev/null
+++ b/npc/012-3-3/manatree.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// The Manatree.
+// THIS IS A PLACEHOLDER!
+
+012-3-3,39,33,0 script Manatree#012-3-3 NPC_MANATREE,{
+ speech
+ l("Magic is all around."),
+ l("You just must listen to it, and feel it deep inside."),
+ l("Now go, search for the unknown.");
+
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/020-1/_import.txt b/npc/020-1/_import.txt
new file mode 100644
index 00000000..a993b5ed
--- /dev/null
+++ b/npc/020-1/_import.txt
@@ -0,0 +1,39 @@
+// Map 020-1: Tulimshar
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-1/_mobs.txt",
+"npc/020-1/_warps.txt",
+"npc/020-1/adrian.txt",
+"npc/020-1/aisha.txt",
+"npc/020-1/anwar.txt",
+"npc/020-1/bodyguard.txt",
+"npc/020-1/boss.txt",
+"npc/020-1/budifis.txt",
+"npc/020-1/cyndala.txt",
+"npc/020-1/ekinu.txt",
+"npc/020-1/eomie.txt",
+"npc/020-1/froma.txt",
+"npc/020-1/harper.txt",
+"npc/020-1/hocus.txt",
+"npc/020-1/inar.txt",
+"npc/020-1/issay.txt",
+"npc/020-1/itka.txt",
+"npc/020-1/joaquim.txt",
+"npc/020-1/joelin.txt",
+"npc/020-1/jossy.txt",
+"npc/020-1/mahoud.txt",
+"npc/020-1/malivox.txt",
+"npc/020-1/marikel.txt",
+"npc/020-1/marine.txt",
+"npc/020-1/martha.txt",
+"npc/020-1/neko.txt",
+"npc/020-1/nickos.txt",
+"npc/020-1/noke.txt",
+"npc/020-1/odonell.txt",
+"npc/020-1/philip.txt",
+"npc/020-1/popaul.txt",
+"npc/020-1/pusco.txt",
+"npc/020-1/ryan.txt",
+"npc/020-1/sander.txt",
+"npc/020-1/tindris.txt",
+"npc/020-1/vaspina.txt",
+"npc/020-1/wateranimation.txt",
diff --git a/npc/020-1/_mobs.txt b/npc/020-1/_mobs.txt
new file mode 100644
index 00000000..27d030e0
--- /dev/null
+++ b/npc/020-1/_mobs.txt
@@ -0,0 +1,63 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-1: Tulimshar mobs
+020-1,165,77,14,12 monster Maggot 1026,6,5000,10000
+020-1,222,172,54,18 monster Maggot 1026,15,5000,10000
+020-1,282,114,12,39 monster Maggot 1026,5,5000,10000
+020-1,175,209,128,38 monster Desert Scorpion 1078,15,12000,36000
+020-1,59,158,18,26 monster Desert Scorpion 1078,5,12000,36000
+020-1,92,189,58,56 monster Desert Snake 1077,8,18000,72000
+020-1,60,174,23,29 monster Black Slime 1079,4,8500,36000
+020-1,188,216,84,32 monster Maggot 1026,20,5000,10000
+020-1,167,81,21,11 monster Brotherhood Fighter 1081,3,6000,18000
+020-1,279,96,13,15 monster Legion Swordswoman 1066,3,6000,18000
+020-1,74,185,23,46 monster Yellow Slime 1073,6,13500,60000
+020-1,254,226,44,30 monster Desert Snake 1077,4,18000,36000
+020-1,277,248,18,10 monster Thief Slime 1105,3,11500,45000
+020-1,126,200,45,11 monster Giant Maggot 1076,2,36000,120000
+020-1,70,73,10,16 monster Giant Maggot 1076,2,36000,120000
+020-1,70,87,14,16 monster Maggot 1026,6,5000,10000
+020-1,70,74,7,10 monster Thief Slime 1105,1,11500,45000
+020-1,103,187,58,57 monster Fire Goblin 1080,10,8000,50000
+020-1,74,95,0,0 monster Manana Tree 1017,1,420000,240000
+020-1,157,130,123,35 monster Tortuga 1004,20,35000,120000
+020-1,43,180,4,22 monster Blub 1008,1,60000,120000
+020-1,282,249,12,7 monster Blub 1008,1,60000,120000
+020-1,114,119,54,62 monster Little Blub 1007,12,25000,120000
+020-1,294,95,0,0 monster Crocotree 1010,1,420000,240000
+020-1,274,105,0,0 monster Crocotree 1010,1,420000,240000
+020-1,278,125,0,0 monster Crocotree 1010,1,420000,240000
+020-1,259,146,0,0 monster Crocotree 1010,1,420000,240000
+020-1,289,144,0,0 monster Crocotree 1010,1,420000,240000
+020-1,246,160,0,0 monster Crocotree 1010,1,420000,240000
+020-1,215,184,0,0 monster Crocotree 1010,1,420000,240000
+020-1,194,175,0,0 monster Crocotree 1010,1,420000,240000
+020-1,187,157,0,0 monster Crocotree 1010,1,420000,240000
+020-1,172,154,0,0 monster Crocotree 1010,1,420000,240000
+020-1,140,133,0,0 monster Crocotree 1010,1,420000,240000
+020-1,176,137,0,0 monster Crocotree 1010,1,420000,240000
+020-1,156,84,0,0 monster Crocotree 1010,1,420000,240000
+020-1,142,77,0,0 monster Crocotree 1010,1,420000,240000
+020-1,104,183,0,0 monster Crocotree 1010,1,420000,240000
+020-1,80,194,0,0 monster Crocotree 1010,1,420000,240000
+020-1,50,188,0,0 monster Crocotree 1010,1,420000,240000
+020-1,49,169,0,0 monster Crocotree 1010,1,420000,240000
+020-1,71,166,0,0 monster Crocotree 1010,1,420000,240000
+020-1,80,154,0,0 monster Crocotree 1010,1,420000,240000
+020-1,90,138,0,0 monster Crocotree 1010,1,420000,240000
+020-1,67,142,0,0 monster Crocotree 1010,1,420000,240000
+020-1,40,139,0,0 monster Crocotree 1010,1,420000,240000
+020-1,39,125,0,0 monster Crocotree 1010,1,420000,240000
+020-1,77,124,0,0 monster Crocotree 1010,1,420000,240000
+020-1,89,97,0,0 monster Crocotree 1010,1,420000,240000
+020-1,63,83,0,0 monster Crocotree 1010,1,420000,240000
+020-1,55,96,0,0 monster Crocotree 1010,1,420000,240000
+020-1,66,64,0,0 monster Crocotree 1010,1,420000,240000
+020-1,291,254,0,0 monster Crocotree 1010,1,420000,240000
+020-1,285,246,0,0 monster Crocotree 1010,1,420000,240000
+020-1,116,251,23,3 monster Mister Prickel 1085,1,100000,200000
+020-1,64,88,6,6 monster Mister Prickel 1085,1,100000,200000
+020-1,268,249,9,3 monster Mister Prickel 1085,1,100000,200000
+020-1,70,132,13,12 monster Fire Wisp 1115,3,10000,60000
+020-1,70,86,12,10 monster Water Wisp 1116,1,10000,60000
+020-1,244,236,47,21 monster Serqet 1119,2,12000,60000
+020-1,228,222,50,19 monster Fire Goblin 1080,5,8000,50000
diff --git a/npc/020-1/_warps.txt b/npc/020-1/_warps.txt
new file mode 100644
index 00000000..30dc8dd5
--- /dev/null
+++ b/npc/020-1/_warps.txt
@@ -0,0 +1,46 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-1: Tulimshar warps
+020-1,166,242,0 warp #020-1_166_242 1,0,020-1,165,250
+020-1,166,249,0 warp #020-1_166_249 1,0,020-1,165,241
+020-1,169,135,0 warp #020-1_169_135 0,0,020-2-0,36,40
+020-1,140,71,0 warp #020-1_140_71 0,0,020-2-1,35,38
+020-1,146,70,0 warp #020-1_146_70 0,0,020-2-1,47,36
+020-1,141,59,0 warp #020-1_141_59 0,0,020-2-2,37,22
+020-1,166,77,0 warp #020-1_166_77 0,0,020-2-3,45,33
+020-1,179,98,0 warp #020-1_179_98 0,0,020-2-4,35,28
+020-1,281,85,0 warp #020-1_281_85 0,0,020-2-5,34,30
+020-1,291,88,0 warp #020-1_291_88 0,0,020-2-5,45,37
+020-1,289,80,0 warp #020-1_289_80 0,0,020-2-6,31,29
+020-1,290,72,0 warp #020-1_290_72 0,0,020-2-6,37,22
+020-1,293,106,0 warp #020-1_293_106 0,0,020-2-7,35,32
+020-1,292,130,0 warp #020-1_292_130 0,0,020-2-8,35,32
+020-1,280,140,0 warp #020-1_280_140 0,0,020-2-9,44,36
+020-1,294,148,0 warp #020-1_294_148 0,0,020-2-11,38,31
+020-1,264,152,0 warp #020-1_264_152 0,0,020-2-10,45,32
+020-1,259,152,0 warp #020-1_259_152 0,0,020-2-10,34,32
+020-1,295,163,0 warp #020-1_295_163 0,0,020-2-12,38,31
+020-1,290,157,0 warp #020-1_290_157 0,0,020-2-13,40,31
+020-1,279,168,0 warp #020-1_279_168 0,0,020-2-14,42,33
+020-1,267,181,0 warp #020-1_267_181 0,0,020-2-15,45,32
+020-1,270,173,0 warp #020-1_270_173 0,0,020-2-16,32,25
+020-1,254,165,0 warp #020-1_254_165 0,0,020-2-17,40,26
+020-1,225,190,0 warp #020-1_225_190 0,0,020-2-18,45,33
+020-1,219,190,0 warp #020-1_219_190 0,0,020-2-18,35,33
+020-1,200,186,0 warp #020-1_200_186 0,0,020-2-19,40,26
+020-1,194,168,0 warp #020-1_194_168 0,0,020-2-20,35,37
+020-1,202,168,0 warp #020-1_202_168 0,0,020-2-20,49,37
+020-1,161,146,0 warp #020-1_161_146 0,0,020-2-21,40,26
+020-1,153,131,0 warp #020-1_153_131 0,0,020-2-22,42,32
+020-1,163,72,0 warp #020-1_163_72 0,0,020-2-23,32,28
+020-1,194,162,0 warp #020-1_194_162 0,0,020-2-24,32,28
+020-1,149,128,0 warp #020-1_149_128 0,0,020-2-25,32,28
+020-1,157,128,0 warp #020-1_157_128 0,0,020-2-25,42,28
+020-1,67,116,0 warp #020-1_67_116 0,0,020-2-26,71,43
+020-1,59,117,0 warp #020-1_59_117 1,0,020-2-26,58,45
+020-1,49,115,0 warp #020-1_49_115 0,0,020-2-26,44,41
+020-1,41,118,0 warp #020-1_41_118 0,0,020-2-26,34,48
+020-1,56,107,0 warp #020-1_56_107 0,0,020-2-28,34,32
+020-1,60,107,0 warp #020-1_60_107 0,0,020-2-28,42,32
+020-1,87,114,0 warp #020-1_87_114 0,0,020-2-29,53,33
+020-1,71,56,0 warp #020-1_71_56 0,0,020-2-31,34,30
+020-1,72,44,0 warp #020-1_72_44 0,0,020-2-33,37,22
diff --git a/npc/020-1/adrian.txt b/npc/020-1/adrian.txt
new file mode 100644
index 00000000..6783c004
--- /dev/null
+++ b/npc/020-1/adrian.txt
@@ -0,0 +1,42 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// Adrian, a Sailor near the Legion's Docks.
+// THIS IS A PLACEHOLDER!
+
+020-1,272,138,0 script Adrian NPC_ADRIAN,{
+ .@q=getq(TonoriQuest_Kylian);
+
+ speech
+ l("Hi there."),
+ l("I was just having a nap, now the port authority summons me to stand here! I hate this job."),
+ l("Are you here to pick up luggage? I'd like to go get a beer, but I have to wait here until all the luggage is picked up.");
+ if (.@q != 1)
+ close;
+ select
+ l("I've came to fetch Kylian's luggage."),
+ l("Leave");
+ mes "";
+ if (@menu == 2)
+ close;
+ mesn;
+ mesc l("%s examines the ticket.", .name$);
+ mesq l("...");
+ next;
+ mesn;
+ mesq l("Mr. Kylian you say? Of course he would send someone to pick up his luggage. Figures.");
+ next;
+ inventoryplace Suitcase, 1;
+ mesn;
+ mesc l("%s hands you a very heavy suitcase.", .name$);
+ mesq l("Here it is. Good luck carrying that thing.");
+ setq1 TonoriQuest_Kylian, 2;
+ getitembound Suitcase, 1, IBT_CHARACTER;
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/aisha.txt b/npc/020-1/aisha.txt
new file mode 100644
index 00000000..51169144
--- /dev/null
+++ b/npc/020-1/aisha.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Aisha, the young lady at Tulim Docks, Legion area.
+// THIS IS A PLACEHOLDER!
+
+020-1,271,93,0 script Aisha NPC_AIRLIA,{
+ speech
+ l("Good day to you, Sir."),
+ l("I totally forgot why I am standing besides that stiky fish, doing nothing."),
+ l("If you have an idea, please tell me what I could do.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/anwar.txt b/npc/020-1/anwar.txt
new file mode 100644
index 00000000..7d6789ef
--- /dev/null
+++ b/npc/020-1/anwar.txt
@@ -0,0 +1,148 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// Anwar, the farmer in Tulimshar.
+
+020-1,178,196,0 script Anwar NPC_ANWAR,{
+ // This code is from Moubootaur Legends and needs cleaning up
+ .@q=getq(TulimsharQuest_AnwarField);
+ if (BaseLevel < 18) {
+ hello;
+ end;
+ }
+
+ if (.@q > 10) goto L_Complete;
+ if (.@q == 10) goto L_SecondReward;
+ if (.@q == 9) goto L_FirstReward;
+ if (.@q == 8) goto L_SecondTry;
+ if (.@q == 7) goto L_AnwarField;
+ if (.@q == 6) goto L_FirstTry;
+ if (.@q == 5) goto L_TryIt;
+ if (.@q >= 1) goto L_FirstTry;
+ // TODO: "What is this contraband fake potion you have there?! I do not accept potions without the seal of the Magic Academy. They might not work and I won't have warranty."
+
+ speech
+ l("Hi there."),
+ l("Nothing grows in this stupid desert."),
+ l("I could try to water it, but where to get water.. also a fertility potion could help."),
+ l("Maybe you can do a small errand for me?");
+ //l("But I have no water, no potion, no script. *cries* ");
+ select
+ l("Sure!"),
+ l("I'm busy, sorry.");
+ mes "";
+ if (@menu == 1)
+ goto L_Sure;
+ close;
+
+L_Complete:
+ mesn;
+ mesq l("Thanks for saving Tulimshar from a famine. I'll be forever grateful.");
+ next;
+ mesn;
+ mesq l("Dealing with raijin is too bothersome to me.");
+ close;
+
+L_AnwarField:
+ mesn;
+ mesq l("My crops! Hurry up, and talk to Hocus!!");
+ close;
+
+L_Sure:
+ mes "";
+ mesn;
+ mesq l("Great! Hocus, the magic academy grandmaster, is a real Nature mage. He probably makes fertilizers.");
+ next;
+ mesn;
+ mesq l("Please, talk to him. I am too busy tending the crops to go myself.");
+ setq TulimsharQuest_AnwarField, 1;
+ close;
+
+L_FirstTry:
+ mesn;
+ mesq l("Good luck getting the fertilizer from Hocus!");
+ if (countitem(FertilityPotion))
+ mesc l("Anwar will only accept fertility potions certified by the Magic Academy.");
+ close;
+
+L_TryIt:
+ .@q2=getq2(TulimsharQuest_AnwarField);
+ if (!countitem(FertilityPotion)) {
+ mesn;
+ mesq l("Bring me the fertilizer!");
+ close;
+ }
+ mesn;
+ mesq l("You've brought me fertilizer! Let me see if it works...");
+ next;
+ delitem FertilityPotion, 1;
+ setq2 TulimsharQuest_AnwarField, .@q2+1;
+
+ // Fail chances are 100% - 13% per attempt
+ if (rand2(0,100) < 100-(.@q2*13)) {
+ setq1 TulimsharQuest_AnwarField, 6;
+ mesc l("Nothing happens.");
+ next;
+ mesn;
+ mesq l("Uhm, it was not enough. Please bring me another one.");
+ } else {
+ setq1 TulimsharQuest_AnwarField, 7;
+ mesc l("Evil worms crawl from earth and starts devouring the plants!");
+ // Okay, maybe Galimatia's potion was a better idea.
+ next;
+ mesn;
+ mesq l("Uh... That should not happen, right? RIGHT?");
+ next;
+ mesn;
+ mesq l("Don't just stand here! Go fetch help, NOW!!");
+ }
+
+ close;
+
+L_SecondTry:
+ if (!countitem(PurificationPotion)) {
+ mesn;
+ mesq l("Bring me the bug bomb or whatever!");
+ close;
+ }
+ mesn strcharinfo(0);
+ mesq l("Here is a certified(R) purification potion! Hocus just gave me. Hurry up!");
+ next;
+ delitem PurificationPotion, 1;
+ getexp 20, 0;
+ specialeffect(51);
+ setq TulimsharQuest_AnwarField, 9;
+ mesn;
+ mesq l("Thanks God... The crops are safe. Not only that, but the fertilizer works!");
+ next;
+ mesn;
+ mesq l("Ah, that was tiresome... I'll go make a reward for them, talk to me again later.");
+ close;
+
+L_FirstReward:
+ mesn;
+ mesq l("Here are two %s. Please deliver it to them. I hope they'll like it.", getitemlink(SilverBell));
+ setq TulimsharQuest_AnwarField, 10, 0;
+ getitembound(SilverBell, 2, 4); // Prevent accidental item loss
+ close;
+
+L_SecondReward:
+ .@q2=getq2(TulimsharQuest_AnwarField);
+ if (.@q2 < 3){
+ mesn;
+ mesq l("Please deliver the two %s to Eomie and Hocus, and then I'll give you something for your help.", getitemlink(SilverBell));
+ close;
+ }
+ setq TulimsharQuest_AnwarField, 11, 0;
+ getitem SilkPants, 1;
+ getexp 750, 0;
+ mesn;
+ mesq l("Many thanks for your help! Here, take this. I'm sure it can be very useful later. It always is.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/bodyguard.txt b/npc/020-1/bodyguard.txt
new file mode 100644
index 00000000..13aea996
--- /dev/null
+++ b/npc/020-1/bodyguard.txt
@@ -0,0 +1,53 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Bodyguard protecting Micksha's chilling place in oasis.
+
+020-1,292,245,0 script Bodyguard NPC_RAIJIN_FEMALE_LEGION_ARTIS,{
+ speech
+ l("Hey, you!"),
+ l("Do not dare sitting on this bench. This is Micksha's place to relax. You better are gone when he arrives."),
+ l("He has to listen to much drama, so he wants to rest here, alone, in silence. Got it?");
+ next;
+ select
+ l("Got it."),
+ l("And what if I sit?"),
+ l("Who's Micksha?"),
+ l("What's the story of this place, anyway?");
+ mes "";
+ mesn;
+ switch (@menu) {
+ case 2:
+ mesq l("Well, if he sees you, a giant foot will descend from the heavens upon you... Or so I've heard.");
+ next;
+ mesn;
+ mesc l("*shivers*");
+ mesq l("I would be afraid if I were you!");
+ next;
+ mesn;
+ break;
+ case 3:
+ mesq l("A popular designer and inventor. A lot of buildings follow their architectonic drawings.");
+ next;
+ mesn;
+ mesq l("You would be amazed at how much engineers and politicians oppose to his architecture, though!");
+ next;
+ mesn;
+ break;
+ case 4:
+ mesq l("Once upon a long time, a local nobleman crushed a gold ingot in this lake. Instead of dust, it became water and then, this pond came to be.");
+ next;
+ mesn;
+ mesq l("It is only a myth, don't expect it to make a lot of sense.");
+ next;
+ mesn;
+ break;
+ }
+ mesq l("Now, get moving.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/boss.txt b/npc/020-1/boss.txt
new file mode 100644
index 00000000..e45eebed
--- /dev/null
+++ b/npc/020-1/boss.txt
@@ -0,0 +1,43 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Description:
+// Controls the boss on 020-1 and the Master Book Learning
+// see npc/items/master_skillbook.txt for explanation about variables
+
+020-1,0,0,0 script #BossCtrl_020-1 NPC_HIDDEN,{
+ end;
+
+// Test server: 5 minutes only
+OnTimer300000:
+ if (!debug)
+ end;
+
+// Otherwise, respawn every 15 minutes
+OnTimer900000:
+ stopnpctimer;
+OnInit:
+ $@MB_0201=0;
+ monster "020-1", 160, 254, strmobinfo(1, GoldenScorpion), GoldenScorpion, 1, "#BossCtrl_020-1::OnBossDeath";
+ end;
+
+OnBossDeath:
+ initnpctimer;
+ BossSlain(.name$, "$@MB_0201");
+ end;
+
+OnBossCheck:
+ @mb_BossId=-1;
+ // TODO: Check if you really fought or was just lurking
+ // Check if party is correct
+ if (getcharid(1) != $@MB_0201)
+ end;
+OnBegin:
+ @mb_BossId=GoldenScorpion;
+ @mb_SkillId=GC_DARKILLUSION;
+ @mb_ItemId=MagicFeather; // Placeholder
+ @mb_ItemAm=1;
+ addtimer(15000, "#MasterBook::OnUnset");
+ end;
+
+}
diff --git a/npc/020-1/budifis.txt b/npc/020-1/budifis.txt
new file mode 100644
index 00000000..763d671b
--- /dev/null
+++ b/npc/020-1/budifis.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Budifis the Water Mage.
+// THIS IS A PLACEHOLDER!
+
+020-1,70,47,0 script Budifis NPC_MAGE_BLUE,{
+ speech
+ l("Hi!"),
+ l("I just love watching the ocean from up there."),
+ l("Did you meet Pusco already? He and his crappy Fire Elements. One day I will extinguish him properly, be assured.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+
diff --git a/npc/020-1/cyndala.txt b/npc/020-1/cyndala.txt
new file mode 100644
index 00000000..3a1a6886
--- /dev/null
+++ b/npc/020-1/cyndala.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Cyndala, a lady in the garden in Tulimshar slums.
+// THIS IS A PLACEHOLDER!
+
+020-1,285,156,0 script Cyndala NPC_INYA,{
+ speech
+ l("Hi there."),
+ l("There used to be more pirates around here, but, you know."),
+ l("People are going mad rewriting history and I'm clueless."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/ekinu.txt b/npc/020-1/ekinu.txt
new file mode 100644
index 00000000..2e9682c0
--- /dev/null
+++ b/npc/020-1/ekinu.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Ekinu, a Brotherhood Guard protecting the bridge.
+// THIS IS A PLACEHOLDER!
+
+020-1,170,118,0 script Ekinu NPC_RAIJIN_MALE_BROTHERHOOD,{
+ speech
+ l("Hi!"),
+ l("You come from Hurnscald? Oh, did you meet my Grandma there? Is she fine?"),
+ l("Tell her greetings, and give her some flowers from me when you return there.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/eomie.txt b/npc/020-1/eomie.txt
new file mode 100644
index 00000000..7b613c38
--- /dev/null
+++ b/npc/020-1/eomie.txt
@@ -0,0 +1,192 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Jesusalva
+// Description:
+// Eomie, the real Nature Mage. Whatever Hocus is saying.
+// ANWAR QUEST PART IS COPY-PASTA FROM MOUBOOTAUR LEGENDS
+// THIS IS A PLACEHOLDER!! The Nature Magic questline is missing.
+
+020-1,76,96,0 script Eomie NPC_EOMIE,{
+ .@q=getq(TulimsharQuest_AnwarField);
+
+ // Results: 6 - nothing. 7- bug feast.
+ // On status 7, you need to talk to Hocus.
+ // Then Hocus will finish stuff for you, and it's reward time.
+ if (.@q == 10) goto L_Gift;
+ if (.@q == 7) goto L_Success;
+ if (.@q == 6) goto L_Fail;
+ if (.@q == 4) goto L_Craft;
+ if (.@q == 3) goto L_Back;
+ if (.@q == 2) goto L_Start;
+ if (.@q == 1) goto L_Refuse;
+
+ // Placeholder dialog
+ if (.@q == 5)
+ mesc l("I still have Anwar's fertilizer with me.");
+ speech
+ l("Hi!"),
+ l("Did you talk to Hocus already? He will tell you about salad, again."),
+ l("Sometimes I think he is more a chef than a mage, but oh well, everybody should do what suits them best.");
+ close;
+
+// READ THE HOLY DIALOGS!!
+L_Refuse:
+ mesn strcharinfo(0);
+ mesq l("Hello! Anwar sent me to get fertilizer to save Tulimshar from famine, could you help me?");
+ next;
+ mesn;
+ mesq l("Not now, I'm busy tending the garden.");
+ close;
+
+L_Start:
+ mesn strcharinfo(0);
+ mesq l("Hello, could I help you in exchange for fertilizer?");
+ next;
+ mesn;
+ mesq l("Actually, yes. The birthday of me and my boyfriend is coming up. He always give me chocolate cake, so I want to surprise him for once. Bring me 12 @@ and I'll make the fertilizer for you.", getitemlink(CherryCake));
+ setq TulimsharQuest_AnwarField, 3;
+ close;
+
+L_Back:
+ mesn;
+ mesq l("So, did you brought me the twelve cherry cakes?");
+ mes "";
+ mesn strcharinfo(0);
+ if (askyesno() != ASK_YES) {
+ close;
+ }
+ mes "";
+ if (countitem("CherryCake") < 12)
+ goto L_Lying;
+
+ delitem CherryCake, 12;
+ getexp 200, 5;
+ setq TulimsharQuest_AnwarField, 4;
+ mesn;
+ mesq l("Okay, that is very useful. However, I do need a few reagents to make it.");
+ next;
+ mesn;
+ mesq l("Please, come back later. I'll see whatever I can fetch for that.");
+ close;
+
+L_Craft:
+ mesn;
+ mesq l("So, for the fertilizer. The thing is, all that thing is unstable.");
+ next;
+ mesn;
+ mesq l("This fertilizer is projected to protect the plants from plagues, bugs, scorpions and maggots, trying to not be a plague itself.");
+ next;
+ mesn;
+ mesq l("I have no way to know how much fertilizer you'll be needing. I need @@ @@ and @@ @@ to make a Certified Fertility Potion for you.", 3, getitemlink(Plushroom), 9, getitemlink(MaggotSlime));
+ next;
+ mesn;
+ mesq l("Give that to whoever needs them, and see if it works. Then come tell me the result. Do you have the reagents?");
+ if (askyesno() != ASK_YES)
+ close;
+ mes "";
+
+ if (countitem(Plushroom) < 3||
+ countitem(MaggotSlime) < 9)
+ goto L_Lying;
+
+ inventoryplace FertilityPotion, 1;
+ delitem Plushroom, 3;
+ delitem MaggotSlime, 9;
+ getitembound(FertilityPotion, 1, IBT_CHARACTER);
+ setq1 TulimsharQuest_AnwarField, 5;
+
+ mesn;
+ mesq l("Here it is. Come back to report the results.");
+ close;
+
+L_Fail:
+ setq1 TulimsharQuest_AnwarField, 4;
+ .@q2=getq2(TulimsharQuest_AnwarField);
+ if (.@q2 < 10)
+ getexp 180-(.@q2*10), 0;
+ else
+ getexp 90, 0;
+ mesn;
+ switch (.@q2) {
+ case 1:
+ mesq l("Well, that could not be enough, I said. Here is some experience.");
+ break;
+ case 2:
+ mesq l("Don't worry, third time is the charm. Here is some experience. Let's try again.");
+ break;
+ case 3:
+ mesq l("Okay, here is some experience, and forgot what I've said before. We can try again.");
+ break;
+ case 4:
+ mesq l("Don't worry, I've tweaked my formula this time. Here is some experience and let's try again!");
+ break;
+ case 5:
+ mesq l("I'm sorry, I just... Maybe if...? Aha! Here's the EXP, ready for a next go?");
+ break;
+ case 6:
+ mesq l("Uhm, maybe I mashed the Plushroom too hard this time. Here's EXP as usual, let's try again?");
+ break;
+ case 7:
+ mesq l("I shall not fail any further, I think my new formula is perfect! Here's the EXP, but I need material to use it!");
+ break;
+ case 8:
+ mesq l("I never knew you could fail THAT hard. I've took Saulc's Fertilizer's recipe, success chance is of 100% if you want to try again.");
+ break;
+ default:
+ mesq l("Well, that could fail, I said. Here is some experience.");
+ break;
+ }
+ next;
+ if (countitem(Plushroom) >= 3 &&
+ countitem(MaggotSlime) >= 9)
+ goto L_Craft;
+ mesn;
+ mesq l("Now go, and fetch the materials again. I'll make another fertilizer for you.");
+ close;
+
+L_Success:
+ mesn;
+ mesq l("WHAT? The farm is plagued with insects?!");
+ next;
+ mesn;
+ mesq l("Quick, tell that to Hocus. No one is better at Nature Magic than Hocus, I'm sure he can help.");
+ close;
+
+L_Gift:
+ .@q2=getq2(TulimsharQuest_AnwarField);
+ if (.@q2 & 1) {
+ mesn;
+ mesq l("Thanks for the nice gift!");
+ close;
+ }
+ // Tip. WHAT DID YOU DID WITH THE BOUND ITEM? IT SHOULD BE HARD TO GET RID OF IT...
+ if (countitem(SilverBell) < 1) {
+ mesn;
+ mesq l("Ah, I wish I got something for helping people out...");
+ close;
+ }
+ mesn strcharinfo(0);
+ mesq l("Anwar sent you this, erm, hum... @@.", getitemlink(SilverBell));
+ next;
+ setq2 TulimsharQuest_AnwarField, .@q2+1;
+ delitem SilverBell, 1;
+ getexp 95, 1;
+ mesn;
+ mesq l("WOW, THIS IS AWESOME! Many, many thanks!!");
+ close;
+
+L_Lying:
+ mesn;
+ mesq l("Ah, so you think you can fool me?");
+ next;
+ percentheal -5, -5;
+ warp "Save", 0, 0;
+ dispbottom l("Ah... Was I warped?");
+ closedialog;
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/froma.txt b/npc/020-1/froma.txt
new file mode 100644
index 00000000..8e232599
--- /dev/null
+++ b/npc/020-1/froma.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Froma, a Legion Soldier besides the gate to Legion area.
+// THIS IS A PLACEHOLDER!
+
+020-1,291,123,0 script Froma NPC_DEMON_MALE_LEGION_ARTIS,{
+ speech
+ l("Fromage!"),
+ l("It is the only word in french I know. We are very classy."),
+ l("So if you want, you can hunt something, or cook something, or craft somethig."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/harper.txt b/npc/020-1/harper.txt
new file mode 100644
index 00000000..104c2f47
--- /dev/null
+++ b/npc/020-1/harper.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Harper, a Sailor helping Joelin.
+// THIS IS A PLACEHOLDER!
+
+020-1,191,150,0 script Harper NPC_ADRIAN,{
+ speech
+ l("Hello!"),
+ l("Ever saw a Captain without a ship?"),
+ l("<--- I am with stupid.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/hocus.txt b/npc/020-1/hocus.txt
new file mode 100644
index 00000000..fcfbe73c
--- /dev/null
+++ b/npc/020-1/hocus.txt
@@ -0,0 +1,166 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Hocus, the Nature Mage and Academy Grandmaster. More interested in food than in nature magic, sometimes.
+// "Hocus: the mages here? They just think they work for me, they never understod that i am just one of them.. no idea why they follow me"
+// THIS IS A PLACEHOLDER!
+
+020-1,73,91,0 script Hocus NPC_MAGE_BROWN,{
+ function anwarNotMe;
+ function anwarFirstAid;
+ function anwarGift;
+
+ setq2 TonoriQuest_Kylian, getq2(TonoriQuest_Kylian) | KYLIAN_HOCUS;
+ speech
+ l("Hi!"),
+ l("You should eat more salad. I see in your face that your nutrition is not good."),
+ l("Can you bug Jesusalva? I really would like to teach you something.");
+ if (getq(HurnscaldQuests_Rossy) == 8) {
+ next;
+ mesn;
+ mesq l("I see you are helping the little girl, Rossy I believe? Her profesor, Mr. David, is on the west wing of the magic academy building.");
+ }
+ next;
+ select
+ rif(getq(General_Cooking) == 15, l("Please enlighten me, O Grandmaster, where can I find Salad to improve my eating habits?")),
+ rif(getq(General_Cooking) == 16, l("I've brought you the promised.")),
+ rif(getq(TulimsharQuest_AnwarField) == 1, l("Hello, do you make Fertility Potions?")),
+ rif(getq(TulimsharQuest_AnwarField) == 7, l("HELP! Anwar field is under worm attack!!")),
+ rif(getq(TulimsharQuest_AnwarField) == 10, l("Anwar sent you a gift.")),
+ l("Thanks for your wise words.");
+ mes "";
+ switch (@menu) {
+ /* Food Questline */
+ case 1:
+ mesn;
+ mesq l("Here. But you probably won't be coming here to eat all the time, so I will teach you a salad recipe.");
+ next;
+ select
+ l("Do you need some monster killed?"),
+ l("Do you need some sort of item?"),
+ l("Do you need money?");
+ mes "";
+ mesn;
+ mesq l("Hm, not really...");
+ next;
+ mesn strcharinfo(0);
+ // FIXME: Carrot Cake? Really??
+ mesq l("I'll bring you 6 %s, 6 %s, and a %s just wait here. I'll also clean up all monsters on the proximity and pay you 1000 E. Wait for my return, Grandmaster!", getitemlink(RoastedAcorn), getitemlink(Carrot), getitemlink(CarrotCake));
+ setq1 General_Cooking, 16;
+ break;
+ case 2:
+ if (countitem(RoastedAcorn) < 6 ||
+ countitem(Carrot) < 6 ||
+ countitem(CarrotCake) < 1 ||
+ Zeny < 1000) {
+ mesn strcharinfo(0);
+ mesc l("I promised to bring him 6 %s, 6 %s, and a %s. I also promised clean up all monsters on the proximity and pay him 1000 E. I'll make the Grandmaster proud!", getitemlink(RoastedAcorn), getitemlink(Carrot), getitemlink(CarrotCake));
+ close;
+ }
+ mesn;
+ mesq l("Child, I do not need your money nor your items. I told you I would teach you the recipe. It is free.");
+ next;
+ mesn;
+ mesq l("I am already happy enough that you want to improve your own eating habits. You don't need to give me anything.");
+ next;
+ mesn;
+ mesq l("Besides, helping each other, even without a compensation is a good thing and accepting help is nothing to be ashamed of. Here. Go in peace, child.");
+ // FIXME: Probably wrong recipe
+ RECIPES[CraftBlueberryCake]=true;
+ RECIPES[CraftCarrotCake]=true;
+ getitem BlueberryCake, 1;
+ setq1 General_Cooking, 17;
+ break;
+ // Anwar Quest
+ case 3:
+ anwarNotMe();
+ break;
+ case 4:
+ anwarFirstAid();
+ break;
+ case 5:
+ anwarGift();
+ break;
+ }
+ close;
+
+function anwarNotMe {
+ mesn strcharinfo(0);
+ mesq l("Hello Mr. Hocus, kind sir Anwar sent me to fetch some fertilizers to save Tulimshar from famine, if you may?");
+ next;
+ mesn;
+ mesq l("Sorry kind friend @@, but no.", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("Or rather, I can't. I would love to help you, just like everybody else, but I don't know how to make fertilizers, only Salad.");
+ next;
+ mesn;
+ mesq l("Eomie probably could do that, she is young but very talented. If you help her, she'll likely help you back.");
+ setq TulimsharQuest_AnwarField, 2;
+ return;
+}
+
+function anwarFirstAid {
+ mesn;
+ mesq l("The crops are under attack? That's terrible!");
+ next;
+ mesn;
+ mesq l("I can do a Certified Purification Potion right away, the warranty covers it. But I still need a few things for it!");
+ next;
+ mesn;
+ mesq l("Do you, perchance, have 2 @@, 2 @@ and 3 @@?", getitemlink(LeftScorpionClaw), getitemlink(RightScorpionClaw), getitemlink(Moss));
+ if (askyesno() != ASK_YES)
+ close;
+ mes "";
+
+ if (countitem(LeftScorpionClaw) < 2 ||
+ countitem(RightScorpionClaw) < 2 ||
+ countitem(Moss) < 3) {
+ mesn;
+ mesq l("Why are you lying? We must cooperate with each other if we want to strive. Otherwise, just like the plants, we will wither and die out. Go fetch the items!");
+ close;
+ }
+
+ inventoryplace PurificationPotion, 1;
+ delitem LeftScorpionClaw, 2;
+ delitem RightScorpionClaw, 2;
+ delitem Moss, 3;
+ getitembound(PurificationPotion, 1, IBT_CHARACTER);
+ setq TulimsharQuest_AnwarField, 8;
+
+ mesn;
+ mesq l("Quick, deliver this to Anwar!");
+ return;
+}
+
+function anwarGift {
+ .@q2=getq2(TulimsharQuest_AnwarField);
+ if (.@q2 & 2) {
+ mesn;
+ mesq l("Thanks for the nice gift!");
+ close;
+ }
+ // Tip. WHAT DID YOU DID WITH THE BOUND ITEM? IT SHOULD BE HARD TO GET RID OF IT...
+ if (countitem(SilverBell) < 1) {
+ mesn;
+ mesq l("Ah, I wish I got something for helping people out...");
+ close;
+ }
+ mesn strcharinfo(0);
+ mesq l("Anwar sent you this, erm, hum... @@.", getitemlink(SilverBell));
+ next;
+ setq2 TulimsharQuest_AnwarField, .@q2+2;
+ delitem SilverBell, 1;
+ getexp 75, 10;
+ mesn;
+ mesq l("WOW, THIS IS AWESOME! Many, many thanks!!");
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+
diff --git a/npc/020-1/inar.txt b/npc/020-1/inar.txt
new file mode 100644
index 00000000..0611eeb6
--- /dev/null
+++ b/npc/020-1/inar.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Inar, a saleswoman in Tulimshar Market.
+// THIS IS A PLACEHOLDER!
+
+020-1,212,171,0 script Inar NPC_SABINE,{
+ speech
+ l("Hi there."),
+ l("You wonder why here are so many idle market stalls, right?"),
+ l("This is due to lazyness of Micksha to prepare placeholders."),
+ l("So, see you later when we have something to sell here.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/issay.txt b/npc/020-1/issay.txt
new file mode 100644
index 00000000..968e58c5
--- /dev/null
+++ b/npc/020-1/issay.txt
@@ -0,0 +1,15 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Issay the Barber.
+// THIS IS A PLACEHOLDER!
+
+020-1,227,179,0 script Issay the Barber NPC_GUMI_THE_DYER,{
+ Barber();
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/itka.txt b/npc/020-1/itka.txt
new file mode 100644
index 00000000..9ca9fb50
--- /dev/null
+++ b/npc/020-1/itka.txt
@@ -0,0 +1,48 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Itka, the spammy spammy little girl in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-1,194,175,0 script Itka NPC_GIRL_MILLY,{
+ speech
+ l("Hi there."),
+ l("Come to the bakery! Come to the Market! Come to Prison!"),
+ l("I will improve, promised. Come to the Academy! Come to Oasis!");
+ do
+ {
+ next;
+ select
+ l("Where is the bakery?"),
+ l("Where is the market?"),
+ l("Where is the prison?"),
+ l("Where is the academy?"),
+ l("Where is the oasis?"),
+ l("Why are you doing this?"),
+ l("Okay... Spammy little girl.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ mesn;
+ mesq l("I don't know! %%Q");
+ break;
+ case 6:
+ mesn;
+ mesq l("To pay my studies!");
+ break;
+ default:
+ close;
+ break;
+ }
+ } while (true);
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/joaquim.txt b/npc/020-1/joaquim.txt
new file mode 100644
index 00000000..83c90596
--- /dev/null
+++ b/npc/020-1/joaquim.txt
@@ -0,0 +1,201 @@
+// The Mana World Script, ported from Moubootaur Legends
+// TMW2 Script, ported from TMW-BR
+// TMW2 Author: Jesusalva
+//
+// Creator: Cardinalli
+// Review: Lunovox <rui.gravata@gmail.com>
+//
+// Description:
+// A rather easy quest to give players what to kill.
+// Reward:
+// Mouboo pendant + 20% exp of level 55
+
+020-1,95,133,4 script Joaquim NPC_MAGE_BLUE,{
+ function joaquimTooWeak;
+ function joaquimWeak;
+ function joaquimComplete;
+ function joaquimFinish;
+ function joaquimDoIt;
+ function joaquimReturn;
+ function joaquimRecipe;
+ function joaquimFound;
+ function joaquimMissing;
+ function joaquimStart;
+
+ .@q=getq(TonoriQuest_Joaquim);
+ if (BaseLevel < 36) joaquimTooWeak();
+ if (BaseLevel < 55) joaquimWeak();
+ switch (.@q) {
+ case 0: joaquimStart(); break;
+ case 1: joaquimFound(); break;
+ case 2: joaquimReturn(); break;
+ case 3: joaquimDoIt(); break;
+ case 4: joaquimFinish(); break;
+ default: joaquimComplete(); break;
+ }
+ close;
+
+function joaquimTooWeak {
+ mesn;
+ mesq l("Hmm, why can't I find swamp yellowherb here in the desert...?");
+ close;
+}
+
+function joaquimWeak {
+ mesn;
+ .@r=rand2(1,5);
+ switch (.@r) {
+ case 1:
+ mesq l("Watch out! My wife was gravely wounded the other day. Tonori monsters are no child play!");
+ break;
+ case 2:
+ mesq l("Ah, I hate mushrooms. Perhaps in future, I could use their spikes and mushies.");
+ break;
+ case 3:
+ mesq l("Ah, I hate snakes. Perhaps in future, I could use their tongues.");
+ break;
+ case 4:
+ mesq l("Ah, I love mouboos. But their steaks, hmm. Ah, no, I shouldn't eat that...");
+ break;
+ case 5:
+ mesq l("You should never sell your Cactus Drinks. They have many uses.");
+ break;
+ }
+ close;
+}
+
+function joaquimComplete {
+ mesn;
+ mesq l("Thanks for helping my wife, I'll be forever grateful.");
+ return;
+}
+
+function joaquimFinish {
+ inventoryplace ElixirOfLife, 1, MoubooPendant, 1;
+ getitem ElixirOfLife, 1;
+ getitem MoubooPendant, 1;
+ quest_xp(.maxLevel, 39260);
+ quest_jxp(.maxLevel, 75);
+ setq TonoriQuest_Joaquim, 5;
+ mesn;
+ mesq l("Take this spare @@ I did. It heals fully and instantly, so don't hesit to use it if you're about to die.", getitemlink(ElixirOfLife));
+ next;
+ mesn;
+ mesq l("Thanks for helping my wife! Here is, an %s. May the Mouboo watch over you! o.o", getitemlink(MoubooPendant));
+ return;
+}
+
+function joaquimDoIt {
+ mesn;
+ mesq l("Please help my wife Yumi, on the Clinic!");
+ return;
+}
+
+// Quest Core
+function joaquimStart {
+ mesn;
+ mesq l("Ohhhhh..... Please, help me!!! My wife is gravely wounded!!");
+ next;
+ mesn strcharinfo(0);
+ mesq l("Calm down! How can I help you?");
+ next;
+ mesn;
+ mesq l("My grandmother gave me a recipe of the %s, it can cure anything but death.", getitemlink(ElixirOfLife));
+ next;
+ mesn;
+ mesq l("I don't remember what I need now, but if you give me a moment, I'll get the list.");
+ setq TonoriQuest_Joaquim, 1;
+ return;
+}
+
+function joaquimFound {
+ mesn;
+ mesq l("I can make an %s, I still have a bottle of fairy blood, a few mana pearls, and some other rare ingredients.", getitemlink(ElixirOfLife));
+ mesq l("It is the non-rare ingredients I actually need help with!");
+ next;
+ joaquimRecipe();
+ next;
+ select
+ l("I will do it, don't worry."),
+ rif(countitem(ElixirOfLife), l("I have one here...")),
+ l("Ahh, too many items. Sorry.");
+ mes "";
+ mesn;
+ if (@menu == 1) {
+ mes l("Thanks! Thanks! Savior! Hurry up!");
+ setq TonoriQuest_Joaquim, 2;
+ } else if (@menu == 2) {
+ mes l("Uhm, sorry, I don't trust stuff you get at market. You know.");
+ mes l("Full of agrotoxins, transgenics and whatever. Not safe.");
+ } else {
+ mes l("Oh noes, who nows can help my wife? Please reconsider!");
+ }
+ return;
+}
+
+function joaquimReturn {
+ joaquimRecipe();
+ next;
+ select
+ l("I'll be back later with all ingredients."),
+ l("They're with me.");
+ mes "";
+ if (@menu == 1)
+ close;
+
+ if (countitem(CactusDrink) < 100 ||
+ countitem(HardSpike) < 60 ||
+ countitem(SmallMushroom) < 45 ||
+ countitem(SnakeTongue) < 40 ||
+ countitem(BottleOfWater) < 30 ||
+ countitem(BugLeg) < 20 ||
+ countitem(MoubooSteak) < 15)
+ joaquimMissing();
+
+ inventoryplace ElixirOfLife, 1;
+
+ delitem CactusDrink, 100;
+ delitem HardSpike, 60;
+ delitem SmallMushroom, 45;
+ delitem SnakeTongue, 40;
+ delitem BottleOfWater, 30;
+ delitem BugLeg, 20;
+ delitem MoubooSteak, 15;
+ getitem ElixirOfLife, 1;
+ setq TonoriQuest_Joaquim, 3;
+ mesn;
+ mesq l("Thanks, I'll just bake the Elixir right away...!");
+ next;
+ mesc l("%s goes away for a while and returns briefly.", .name$);
+ next;
+ mesn;
+ mesq l("Here, take the Elixir. Please, bring it to my wife! I am counting on you!!");
+ return;
+}
+
+function joaquimMissing {
+ mesn strcharinfo(0);
+ mesq l("Except they're not. I'll be back later.");
+ next;
+ mesn;
+ mesq l("Please, %s! Hurry up!", strcharinfo(0));
+ close;
+}
+
+function joaquimRecipe {
+ mesn l("%s Recipe", getitemlink(ElixirOfLife));
+ mesc l("%d/%d %s", countitem(CactusDrink), 100, getitemlink(CactusDrink));
+ mesc l("%d/%d %s", countitem(HardSpike), 60, getitemlink(HardSpike));
+ mesc l("%d/%d %s", countitem(SmallMushroom), 45, getitemlink(SmallMushroom));
+ mesc l("%d/%d %s", countitem(SnakeTongue), 40, getitemlink(SnakeTongue));
+ mesc l("%d/%d %s", countitem(BottleOfWater), 30, getitemlink(BottleOfWater));
+ mesc l("%d/%d %s", countitem(BugLeg), 20, getitemlink(BugLeg));
+ mesc l("%d/%d %s", countitem(MoubooSteak), 15, getitemlink(MoubooSteak));
+ return;
+}
+
+OnInit:
+ .maxLevel = 75;
+ .distance = 5;
+ end;
+}
diff --git a/npc/020-1/joelin.txt b/npc/020-1/joelin.txt
new file mode 100644
index 00000000..820fe276
--- /dev/null
+++ b/npc/020-1/joelin.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Joelin, the broken, shipless Captain in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-1,189,150,0 script Joelin NPC_JOELIN,{
+ speech
+ l("Hello!"),
+ l("Do you know the story of the Fleet of Aemil? I also want to discover new Lands."),
+ l("But I do not have a ship. Ah, right, and no script.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/jossy.txt b/npc/020-1/jossy.txt
new file mode 100644
index 00000000..45440fd8
--- /dev/null
+++ b/npc/020-1/jossy.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Jossy, another Brotherhood Member in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-1,180,87,0 script Jossy NPC_HUMAN_MALE_BROTHERHOOD,{
+ speech
+ l("Hi!"),
+ l("I don't want to talk to you."),
+ l("Here, talk to my hand.");
+ heal -100, 0;
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/mahoud.txt b/npc/020-1/mahoud.txt
new file mode 100644
index 00000000..2ad43518
--- /dev/null
+++ b/npc/020-1/mahoud.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Mahoud, a scammer and a troll besides the Tulimshar Graveyard.
+// THIS IS A PLACEHOLDER!
+
+020-1,180,169,0 script Mahoud NPC_YOUNG_MAN_KFAHR,{
+ speech
+ l("Hey, you!"),
+ l("Got something to bury? I need some job, and I need some money."),
+ l("Ah, wait, we cannot trade anything without some developer. Go find one!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/malivox.txt b/npc/020-1/malivox.txt
new file mode 100644
index 00000000..583574c5
--- /dev/null
+++ b/npc/020-1/malivox.txt
@@ -0,0 +1,23 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Malivox, a salesman in Tulimshar Market.
+// THIS IS A PLACEHOLDER!
+
+020-1,241,170,0 script Malivox NPC_KPG_MANAGER,{
+ speech
+ l("Hi there."),
+ l("You wonder why here are so many idle market stalls, right?"),
+ l("This is due to lazyness of Micksha to prepare placeholders."),
+ l("Don't steal stuff from them, though. Or you will be imprisoned."),
+ l("What I sell? Well, you can see Mananas... Aquadas... Croc claws..."),
+ l("But they are not for sale! I use them for my custom brew of status reset potions. Are you interested?");
+
+ ConfirmStatusReset();
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/marikel.txt b/npc/020-1/marikel.txt
new file mode 100644
index 00000000..2619e6fe
--- /dev/null
+++ b/npc/020-1/marikel.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Marikel, another Brotherhood Guard protecting the bridge.
+// THIS IS A PLACEHOLDER!
+
+020-1,163,118,0 script Marikel NPC_HUMAN_MALE_BROTHERHOOD,{
+ speech
+ l("Hi!"),
+ l("You come from Hurnscald? Oh, did you meet my Grandpa there? Is she fine?"),
+ l("Tell him greetings, and give him a few beers from me once you return there.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/marine.txt b/npc/020-1/marine.txt
new file mode 100644
index 00000000..65a08adc
--- /dev/null
+++ b/npc/020-1/marine.txt
@@ -0,0 +1,17 @@
+// Moubootaur Legends scripts.
+// Authors:
+// Jesusalva
+// Description:
+// This script controls access to Ships, fixing variables.
+
+// Use NPC_LA_MARINE if needed
+020-1,210,143,0 script La Marine#T NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ EnterTown("Tulim");
+
+ warp "marine@"+LOCATION$, 42, 26;
+ closedialog;
+ close;
+}
diff --git a/npc/020-1/martha.txt b/npc/020-1/martha.txt
new file mode 100644
index 00000000..2faf9dd3
--- /dev/null
+++ b/npc/020-1/martha.txt
@@ -0,0 +1,18 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Martha, sort of Brotherhood Leader in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-1,164,81,0 script Martha NPC_UKAR_FEMALE_BROTHERHOOD,{
+ speech
+ l("Hi!"),
+ l("Have you ever been to Artis? Did you meet my mom there? Her name is Sophialla."),
+ l("I hope she is fine. It is so dangerous out there.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/neko.txt b/npc/020-1/neko.txt
new file mode 100644
index 00000000..92460cf7
--- /dev/null
+++ b/npc/020-1/neko.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Neko, the Trader in Legion area in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-1,278,99,0 script Neko NPC_DESERT_HAT_MAN,{
+ speech
+ l("Hi there."),
+ l("I am out of stock, unfortunately."),
+ l("What do you mean to look at my wares?!"),
+ l("My collection of random stuff is not for sale! Go away!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/nickos.txt b/npc/020-1/nickos.txt
new file mode 100644
index 00000000..fb4c61be
--- /dev/null
+++ b/npc/020-1/nickos.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Nickos, a free soldier working with Nickos on protecting the town from mine mobs.
+// THIS IS A PLACEHOLDER!
+
+020-1,78,237,0 script Nickos NPC_NICKOS,{
+ speech
+ l("Hi there."),
+ l("Sorry, for now you cannot enter. We sealed the entrance to avoid a monster flood."),
+ l("Come back later, perhaps you can help keeping things under control.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/noke.txt b/npc/020-1/noke.txt
new file mode 100644
index 00000000..74337640
--- /dev/null
+++ b/npc/020-1/noke.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Noke, the Trader in Brotherhood area in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-1,171,80,0 script Noke NPC_DESERT_HAT_MAN,{
+ speech
+ l("Hi there."),
+ l("Everyone wants a slice of Tulimshar."),
+ l("So it is hard to know my role on this world."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/odonell.txt b/npc/020-1/odonell.txt
new file mode 100644
index 00000000..186929ed
--- /dev/null
+++ b/npc/020-1/odonell.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// O'Donell, a member of Thieves Guild protecting their Cave's entrance.
+// THIS IS A PLACEHOLDER!
+
+020-1,157,157,0 script O'Donell NPC_HENRY,{
+ speech
+ l("Psst!"),
+ l("Did you already meet Nunia, in Woodland? If you bring me a stolen good, I will let you inside our Thieves Guild Headquarters."),
+ l("If you don't - well, go play hide'n'seek with Itka. Her spam annoys me anyways.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/philip.txt b/npc/020-1/philip.txt
new file mode 100644
index 00000000..9b575a8c
--- /dev/null
+++ b/npc/020-1/philip.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Philip, a Legion Soldier besides the gate to Legion area.
+// THIS IS A PLACEHOLDER!
+
+020-1,285,123,0 script Philip NPC_UKAR_MALE_LEGION_ARTIS,{
+ speech
+ l("Hi there."),
+ l("I am just a random soldier, so stop bothering me."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/popaul.txt b/npc/020-1/popaul.txt
new file mode 100644
index 00000000..94ed4dcf
--- /dev/null
+++ b/npc/020-1/popaul.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Popaul, a Legion Soldier in Legion area of Tulim.
+// THIS IS A PLACEHOLDER!
+
+020-1,278,108,0 script Popaul NPC_HUMAN_MALE_LEGION_ARTIS,{
+ speech
+ l("Hi there."),
+ l("I am so lazy today. I wish work hours end soon."),
+ l("Then I'll have a drink with my friends at the inn."),
+ l("Won't be able to walk properly afterwards, but whatever, I get experience either way!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/pusco.txt b/npc/020-1/pusco.txt
new file mode 100644
index 00000000..2fc15879
--- /dev/null
+++ b/npc/020-1/pusco.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Pusco, the Fire Mage. Still outside, to be moved to the cave (with some lava) later (TM).
+// THIS IS A PLACEHOLDER!
+
+020-1,87,122,0 script Pusco NPC_MAGE_RED,{
+ speech
+ l("Hi!"),
+ l("Fire, I love fire! Its so powerful! It even comes with particle effects most of the time!"),
+ l("Can you bug Jesusalva? I really would like to teach you something.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+
diff --git a/npc/020-1/ryan.txt b/npc/020-1/ryan.txt
new file mode 100644
index 00000000..7ed14715
--- /dev/null
+++ b/npc/020-1/ryan.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Ryan, a Legion Soldier near the Docks.
+// THIS IS A PLACEHOLDER!
+
+020-1,275,97,0 script Ryan NPC_DEMON_MALE_LEGION_ARTIS,{
+ speech
+ l("hmmm..."),
+ l("You were in Hurnscald lately, right? That smell, that Brotherhood smell."),
+ l("Better get out of here, before I become wild.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/sander.txt b/npc/020-1/sander.txt
new file mode 100644
index 00000000..5eac3386
--- /dev/null
+++ b/npc/020-1/sander.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Sander, a free soldier working with Nickos on protecting the town from mine mobs.
+// THIS IS A PLACEHOLDER!
+
+020-1,200,203,0 script Sander NPC_SANDER,{
+ speech
+ l("Hi there."),
+ l("I will send you to the mines! Later, when we have clearance for the mines, that is."),
+ l("Tell Micksha to get up his ass for mapping desert caves, maybe this will speed it up.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/tindris.txt b/npc/020-1/tindris.txt
new file mode 100644
index 00000000..e35acc2d
--- /dev/null
+++ b/npc/020-1/tindris.txt
@@ -0,0 +1,30 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Tindris, a mage apprentice on the way to magic academy. Twice. It is magic.
+// THIS IS A PLACEHOLDER!
+
+020-1,44,196,0 script Tindris#1 NPC_SIMON,{
+ speech
+ l("Hi!"),
+ l("Past here, the neutral area of the Magic Academy of Tulimshar starts."),
+ l("Don't dare to use any violence against peaceful beings, or you will be punished.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+020-1,46,133,0 script Tindris#2 NPC_SIMON,{
+ speech
+ l("Hi!"),
+ l("Past here, the neutral area of the Magic Academy of Tulimshar starts."),
+ l("Don't dare to use any violence against peaceful beings, or you will be punished.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-1/vaspina.txt b/npc/020-1/vaspina.txt
new file mode 100644
index 00000000..7e5b76bd
--- /dev/null
+++ b/npc/020-1/vaspina.txt
@@ -0,0 +1,20 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Vaspina the Harmony Mage.
+// THIS IS A PLACEHOLDER!
+
+020-1,91,112,0 script Vaspina NPC_MORGAN,{
+ speech
+ l("Hi!"),
+ l("Pst, not so loud. You frighten the animals here."),
+ l("You were told to not harm peaceful beings in the Academy, right? Please strictly follow that rule.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+
diff --git a/npc/020-1/wateranimation.txt b/npc/020-1/wateranimation.txt
new file mode 100644
index 00000000..a539a944
--- /dev/null
+++ b/npc/020-1/wateranimation.txt
@@ -0,0 +1,20 @@
+// The Mana World scripts.
+// Description:
+// Water animations, splash, fishes, etc...
+
+020-1,103,141,0 duplicate(#fish_seawater) #tulim_fish01 NPC_WATER_SPLASH
+020-1,98,144,0 duplicate(#fish_seawater) #tulim_fish02 NPC_WATER_SPLASH
+020-1,94,148,0 duplicate(#fish_seawater) #tulim_fish03 NPC_WATER_SPLASH
+020-1,181,70,0 duplicate(#fish_seawater) #tulim_fish04 NPC_WATER_SPLASH
+020-1,191,94,0 duplicate(#fish_seawater) #tulim_fish05 NPC_WATER_SPLASH
+020-1,182,117,0 duplicate(#fish_seawater) #tulim_fish06 NPC_WATER_SPLASH
+020-1,187,126,0 duplicate(#fish_seawater) #tulim_fish07 NPC_WATER_SPLASH
+020-1,227,159,0 duplicate(#fish_seawater) #tulim_fish08 NPC_WATER_SPLASH
+020-1,238,158,0 duplicate(#fish_seawater) #tulim_fish09 NPC_WATER_SPLASH
+020-1,247,146,0 duplicate(#fish_seawater) #tulim_fish10 NPC_WATER_SPLASH
+020-1,257,127,0 duplicate(#fish_seawater) #tulim_fish11 NPC_WATER_SPLASH
+020-1,263,126,0 duplicate(#fish_seawater) #tulim_fish12 NPC_WATER_SPLASH
+020-1,268,87,0 duplicate(#fish_seawater) #tulim_fish13 NPC_WATER_SPLASH
+020-1,217,155,0 duplicate(#fish_seawater) #tulim_fish14 NPC_WATER_SPLASH
+020-1,295,74,0 duplicate(#fish_seawater) #tulim_fish15 NPC_WATER_SPLASH
+
diff --git a/npc/020-2-0/_import.txt b/npc/020-2-0/_import.txt
new file mode 100644
index 00000000..368dffce
--- /dev/null
+++ b/npc/020-2-0/_import.txt
@@ -0,0 +1,5 @@
+// Map 020-2-0: Ratto Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-0/_mobs.txt",
+"npc/020-2-0/_warps.txt",
+"npc/020-2-0/kaizer.txt",
diff --git a/npc/020-2-0/_mobs.txt b/npc/020-2-0/_mobs.txt
new file mode 100644
index 00000000..dd5d42ba
--- /dev/null
+++ b/npc/020-2-0/_mobs.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-0: Ratto Hut mobs
+020-2-0,40,22,0,0 monster Ratto 1005,1,5000,10000
+020-2-0,35,29,0,0 monster Ratto 1005,1,5000,10000
+020-2-0,41,36,0,0 monster Ratto 1005,1,5000,10000
diff --git a/npc/020-2-0/_warps.txt b/npc/020-2-0/_warps.txt
new file mode 100644
index 00000000..8dcdbe87
--- /dev/null
+++ b/npc/020-2-0/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-0: Ratto Hut warps
+020-2-0,36,41,0 warp #020-2-0_36_41 0,0,020-1,169,136
diff --git a/npc/020-2-0/kaizer.txt b/npc/020-2-0/kaizer.txt
new file mode 100644
index 00000000..0b8819a0
--- /dev/null
+++ b/npc/020-2-0/kaizer.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Kaizer, the guy in the Rat Hut.
+// THIS IS A PLACEHOLDER!
+
+020-2-0,34,33,0 script Kaizer NPC_OLD_MAN_HURNS,{
+ speech
+ l("Welcome to my palace!"),
+ l("Not a palace? What? Are you blind?!?"),
+ l("You better should leave, ofc after helping me kill those annoying rats. That is an order.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-1/_import.txt b/npc/020-2-1/_import.txt
new file mode 100644
index 00000000..d410e471
--- /dev/null
+++ b/npc/020-2-1/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-1: Brotherhood Castle
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-1/_warps.txt",
diff --git a/npc/020-2-1/_warps.txt b/npc/020-2-1/_warps.txt
new file mode 100644
index 00000000..88307a19
--- /dev/null
+++ b/npc/020-2-1/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-1: Brotherhood Castle warps
+020-2-1,35,39,0 warp #020-2-1_35_39 0,0,020-1,140,72
+020-2-1,47,37,0 warp #020-2-1_47_37 0,0,020-1,146,71
+020-2-1,36,29,0 warp #020-2-1_36_29 2,0,020-2-2,32,28
diff --git a/npc/020-2-10/_import.txt b/npc/020-2-10/_import.txt
new file mode 100644
index 00000000..0f59e421
--- /dev/null
+++ b/npc/020-2-10/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-10: Tailor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-10/_warps.txt",
+"npc/020-2-10/hetchel.txt",
diff --git a/npc/020-2-10/_warps.txt b/npc/020-2-10/_warps.txt
new file mode 100644
index 00000000..099f754a
--- /dev/null
+++ b/npc/020-2-10/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-10: Tailor warps
+020-2-10,45,33,0 warp #020-2-10_45_33 0,0,020-1,264,153
+020-2-10,34,33,0 warp #020-2-10_34_33 0,0,020-1,259,153
diff --git a/npc/020-2-10/hetchel.txt b/npc/020-2-10/hetchel.txt
new file mode 100644
index 00000000..faed2b99
--- /dev/null
+++ b/npc/020-2-10/hetchel.txt
@@ -0,0 +1,33 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Hetchel, the silk weaver / tailor in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-2-10,45,27,0 script Hetchel NPC_HETCHEL,{
+ setq2 TonoriQuest_Kylian, getq2(TonoriQuest_Kylian) | KYLIAN_HETCHEL;
+ speech
+ l("Hi there. I am Hetchel, I weave fine textiles."),
+ l("My best client is Lora Tay, at Dimond's."),
+ l("So if you want, you can talk to her instead."),
+ l("Tailoring is in decline and I have nothing to sell nor teach."),
+ l("Unless you want to try doing it yourself?");
+ next;
+ do
+ {
+ mes "";
+ .@s = SmithSystem(CRAFT_TAILORING);
+ if (.@s)
+ mesc l("Success!"), 3;
+ else
+ mesc l("That didn't work!"), 1;
+ next;
+ mesc l("Do you want to continue?");
+ } while (askyesno() != ASK_YES);
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-11/_import.txt b/npc/020-2-11/_import.txt
new file mode 100644
index 00000000..b3a212c8
--- /dev/null
+++ b/npc/020-2-11/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-11: Ramshackle Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-11/_warps.txt",
diff --git a/npc/020-2-11/_warps.txt b/npc/020-2-11/_warps.txt
new file mode 100644
index 00000000..e6c771a5
--- /dev/null
+++ b/npc/020-2-11/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-11: Ramshackle Hut warps
+020-2-11,38,32,0 warp #020-2-11_38_32 0,0,020-1,294,149
diff --git a/npc/020-2-12/_import.txt b/npc/020-2-12/_import.txt
new file mode 100644
index 00000000..f95de8cc
--- /dev/null
+++ b/npc/020-2-12/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-12: Small Garden Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-12/_warps.txt",
diff --git a/npc/020-2-12/_warps.txt b/npc/020-2-12/_warps.txt
new file mode 100644
index 00000000..76cedf4e
--- /dev/null
+++ b/npc/020-2-12/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-12: Small Garden Hut warps
+020-2-12,38,32,0 warp #020-2-12_38_32 0,0,020-1,295,164
diff --git a/npc/020-2-13/_import.txt b/npc/020-2-13/_import.txt
new file mode 100644
index 00000000..a962abca
--- /dev/null
+++ b/npc/020-2-13/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-13: Large Garden Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-13/_warps.txt",
diff --git a/npc/020-2-13/_warps.txt b/npc/020-2-13/_warps.txt
new file mode 100644
index 00000000..ac853a91
--- /dev/null
+++ b/npc/020-2-13/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-13: Large Garden Hut warps
+020-2-13,40,32,0 warp #020-2-13_40_32 0,0,020-1,290,158
diff --git a/npc/020-2-14/_import.txt b/npc/020-2-14/_import.txt
new file mode 100644
index 00000000..2a32c09c
--- /dev/null
+++ b/npc/020-2-14/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-14: Small Slum Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-14/_warps.txt",
diff --git a/npc/020-2-14/_warps.txt b/npc/020-2-14/_warps.txt
new file mode 100644
index 00000000..4165732b
--- /dev/null
+++ b/npc/020-2-14/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-14: Small Slum Hut warps
+020-2-14,42,34,0 warp #020-2-14_42_34 0,0,020-1,279,169
diff --git a/npc/020-2-15/_import.txt b/npc/020-2-15/_import.txt
new file mode 100644
index 00000000..fba37df5
--- /dev/null
+++ b/npc/020-2-15/_import.txt
@@ -0,0 +1,7 @@
+// Map 020-2-15: Tulimshar Clinic
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-15/_warps.txt",
+"npc/020-2-15/eleanore.txt",
+"npc/020-2-15/kadiya.txt",
+"npc/020-2-15/memoriam.txt",
+"npc/020-2-15/yumi.txt",
diff --git a/npc/020-2-15/_warps.txt b/npc/020-2-15/_warps.txt
new file mode 100644
index 00000000..7e260483
--- /dev/null
+++ b/npc/020-2-15/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-15: Tulimshar Clinic warps
+020-2-15,45,33,0 warp #020-2-15_45_33 0,0,020-1,267,182
diff --git a/npc/020-2-15/eleanore.txt b/npc/020-2-15/eleanore.txt
new file mode 100644
index 00000000..f650d96e
--- /dev/null
+++ b/npc/020-2-15/eleanore.txt
@@ -0,0 +1,16 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Description:
+// Elenaore the Healer (aka. Elanore)
+// THIS IS A PLACEHOLDER!
+
+020-2-15,43,27,0 script Eleanore NPC_REBECCA,{
+ mesn;
+ mesq l("Please do not disturb the patients.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-15/kadiya.txt b/npc/020-2-15/kadiya.txt
new file mode 100644
index 00000000..3b25d619
--- /dev/null
+++ b/npc/020-2-15/kadiya.txt
@@ -0,0 +1,21 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Description:
+// Kadiya, Omar's sick daughter
+// THIS IS A PLACEHOLDER!
+
+020-2-15,39,26,0 script Kadiya NPC_TANISHA,{
+ mesn;
+ mesc l("*cough cough*");
+ mesq l("Hello there.");
+ next;
+ mesn;
+ mesc l("*cough cough*");
+ mesq l("Have you seen my father Omar? I bet Micksha took him to drink.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-15/memoriam.txt b/npc/020-2-15/memoriam.txt
new file mode 100644
index 00000000..041c659a
--- /dev/null
+++ b/npc/020-2-15/memoriam.txt
@@ -0,0 +1,19 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Description:
+// Irene Memorial
+
+020-2-15,41,25,0 script Memoriam NPC_PAPER_NOTE,{
+ mes ".:: In Memoriam ::.";
+ mes "";
+ mes "~ Irene Christina ~";
+ mes l("The song in this clinic is dedicated to Irene.");
+ next;
+ mes l("She had seen only twenty hours of this world when she died in her father's arms.");
+ close;
+
+OnInit:
+ .distance = 3;
+ end;
+}
diff --git a/npc/020-2-15/yumi.txt b/npc/020-2-15/yumi.txt
new file mode 100644
index 00000000..5a5e7f0d
--- /dev/null
+++ b/npc/020-2-15/yumi.txt
@@ -0,0 +1,54 @@
+// TMW2 Script
+// Author: Jesusalva
+// Description:
+// Joaquim's wife.
+// TODO sprite on the bed
+
+020-2-15,33,26,0 script Yumi NPC_EOMIE,{
+ .@q=getq(TonoriQuest_Joaquim);
+ if (.@q > 3) goto L_PostAid;
+ if (.@q == 3) goto L_DoIt;
+ if (BaseLevel > 36) goto L_PreAid;
+
+ mesn;
+ mesq l("Hello. Take care with the Snakes, they're highly poisonous!");
+ close;
+
+L_PreAid:
+ mesn;
+ mesq l("Please... Speak low... I am dying........");
+ next;
+ mesn;
+ mesq l("The nurse... Eleanore is... Doing all she can... To help me, though.");
+ close;
+
+L_PostAid:
+ mesn;
+ mesq l("Ah, I am lively again. I wish I could just raise from this bed and do some exercise, but Eleanore refuses to let me go.");
+ // There could be another quest stage her
+ close;
+
+L_DoIt:
+ if (countitem(ElixirOfLife) < 1)
+ goto L_PreAid;
+
+ inventoryplace ElixirOfLife, 1;
+ delitem ElixirOfLife, 1;
+ quest_xp(.maxLevel, 1000);
+ setq TonoriQuest_Joaquim, 4;
+ mesc l("*gulp* *gulp* *gulp*");
+ next;
+ mesn;
+ mesq l("AAAAAAAHHHHH, Thanks, I am lively again!");
+ next;
+ mesn;
+ mesq l("In fact, I am cured! Hooray!!");
+ close;
+
+OnInit:
+ .minLevel = 36;
+ .maxLevel = 66;
+
+ .distance = 5;
+ end;
+}
diff --git a/npc/020-2-16/_import.txt b/npc/020-2-16/_import.txt
new file mode 100644
index 00000000..e73eda08
--- /dev/null
+++ b/npc/020-2-16/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-16: Slum Laundry
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-16/_warps.txt",
diff --git a/npc/020-2-16/_warps.txt b/npc/020-2-16/_warps.txt
new file mode 100644
index 00000000..6eef2fbf
--- /dev/null
+++ b/npc/020-2-16/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-16: Slum Laundry warps
+020-2-16,31,25,0 warp #020-2-16_31_25 0,0,020-1,269,173
diff --git a/npc/020-2-17/_import.txt b/npc/020-2-17/_import.txt
new file mode 100644
index 00000000..3b44100e
--- /dev/null
+++ b/npc/020-2-17/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-17: Fisherman's Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-17/_warps.txt",
diff --git a/npc/020-2-17/_warps.txt b/npc/020-2-17/_warps.txt
new file mode 100644
index 00000000..4675eb7e
--- /dev/null
+++ b/npc/020-2-17/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-17: Fisherman's Hut warps
+020-2-17,40,27,0 warp #020-2-17_40_27 0,0,020-1,254,166
diff --git a/npc/020-2-18/_import.txt b/npc/020-2-18/_import.txt
new file mode 100644
index 00000000..1898daec
--- /dev/null
+++ b/npc/020-2-18/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-18: Market Administration
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-18/_warps.txt",
+"npc/020-2-18/inya.txt",
diff --git a/npc/020-2-18/_warps.txt b/npc/020-2-18/_warps.txt
new file mode 100644
index 00000000..be5cc0b7
--- /dev/null
+++ b/npc/020-2-18/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-18: Market Administration warps
+020-2-18,45,34,0 warp #020-2-18_45_34 0,0,020-1,225,191
+020-2-18,35,34,0 warp #020-2-18_35_34 0,0,020-1,219,191
diff --git a/npc/020-2-18/inya.txt b/npc/020-2-18/inya.txt
new file mode 100644
index 00000000..7a347faa
--- /dev/null
+++ b/npc/020-2-18/inya.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Inya, the jewelery lady in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-2-18,35,25,0 script Inya NPC_INYA,{
+ speech
+ l("Hi there."),
+ l("Gold, Silver, Copper, Platinum. Got anything of that with you?"),
+ l("Just throw it on the ground in here, and bring more."),
+ l("Perhaps one day I will reward you with a few buglegs or such, don't worry.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-19/_import.txt b/npc/020-2-19/_import.txt
new file mode 100644
index 00000000..85597f7c
--- /dev/null
+++ b/npc/020-2-19/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-19: Farmer's Home
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-19/_warps.txt",
diff --git a/npc/020-2-19/_warps.txt b/npc/020-2-19/_warps.txt
new file mode 100644
index 00000000..08a82dd8
--- /dev/null
+++ b/npc/020-2-19/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-19: Farmer's Home warps
+020-2-19,40,27,0 warp #020-2-19_40_27 0,0,020-1,200,187
diff --git a/npc/020-2-2/_import.txt b/npc/020-2-2/_import.txt
new file mode 100644
index 00000000..7f33c28e
--- /dev/null
+++ b/npc/020-2-2/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-2: Brotherhood Tower
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-2/_warps.txt",
diff --git a/npc/020-2-2/_warps.txt b/npc/020-2-2/_warps.txt
new file mode 100644
index 00000000..faa57616
--- /dev/null
+++ b/npc/020-2-2/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-2: Brotherhood Tower warps
+020-2-2,32,29,0 warp #020-2-2_32_29 2,0,020-2-1,36,30
+020-2-2,37,21,0 warp #020-2-2_37_21 0,0,020-1,140,59
diff --git a/npc/020-2-20/_import.txt b/npc/020-2-20/_import.txt
new file mode 100644
index 00000000..8bc63945
--- /dev/null
+++ b/npc/020-2-20/_import.txt
@@ -0,0 +1,5 @@
+// Map 020-2-20: Tulimshar Inn
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-20/_warps.txt",
+"npc/020-2-20/drabur.txt",
+"npc/020-2-20/riskim.txt",
diff --git a/npc/020-2-20/_warps.txt b/npc/020-2-20/_warps.txt
new file mode 100644
index 00000000..3508873e
--- /dev/null
+++ b/npc/020-2-20/_warps.txt
@@ -0,0 +1,6 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-20: Tulimshar Inn warps
+020-2-20,49,38,0 warp #020-2-20_49_38 0,0,020-1,202,169
+020-2-20,35,38,0 warp #020-2-20_35_38 0,0,020-1,194,169
+020-2-20,33,22,0 warp #020-2-20_33_22 0,0,020-2-24,32,24
+020-2-20,37,21,0 warp #020-2-20_37_21 0,0,020-2-34,37,41
diff --git a/npc/020-2-20/drabur.txt b/npc/020-2-20/drabur.txt
new file mode 100644
index 00000000..8ebbb979
--- /dev/null
+++ b/npc/020-2-20/drabur.txt
@@ -0,0 +1,54 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Drabur, the baker's salesman.
+// THIS IS A PLACEHOLDER!
+
+020-2-20,47,30,0 script Drabur NPC_GENERAL_STORE,{
+ mesn;
+ mesq l("Please don't interrupt my work, I am busy.");
+ next;
+ select
+ l("Hi there."),
+ l("Do you sell anything here?"),
+ l("Could I lodge here?"),
+ l("Goodbye.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("...");
+ break;
+ case 2:
+ mesn;
+ mesq l("Sure - take a look.");
+ next;
+ closeclientdialog;
+ shop .name$;
+ break;
+ case 3:
+ mesn;
+ mesq l("Sorry, we've booked our only room to a foreigner called Kylian.");
+ next;
+ mesn;
+ mesq l("And we got rid of the extra beds as no one was using them, so we are full at the moment. Come again later.");
+ break;
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ tradertype(NST_MARKET);
+
+ sellitem BlueberryCake, -1, 1+rand2(10);
+ sellitem CarrotCake, -1, 1+rand2(10);
+ sellitem Donut, -1, 1+rand2(10);
+ end;
+
+OnClock0002:
+ restoreshopitem BlueberryCake, rand2(11);
+ restoreshopitem CarrotCake, rand2(11);
+ restoreshopitem Donut, rand2(11);
+ end;
+}
diff --git a/npc/020-2-20/riskim.txt b/npc/020-2-20/riskim.txt
new file mode 100644
index 00000000..f68b9825
--- /dev/null
+++ b/npc/020-2-20/riskim.txt
@@ -0,0 +1,152 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Riskim, the baker in Tulimshar.
+// THIS IS A PLACEHOLDER!
+
+020-2-20,49,30,0 script Riskim NPC_CHEF_LEGACY,{
+ function foodQuestline;
+ .@q=getq(General_Cooking);
+ speech
+ l("Hi there."),
+ l("Need a Donut?"),
+ l("Well, tell me the recipe and I will bake for you whatever you need, for a small fee."),
+ l("But: No recipe, no desserts.");
+ if (.@q > 10)
+ foodQuestline;
+ close;
+
+function foodQuestline {
+ .@q=getq(General_Cooking);
+ .@q2=getq2(General_Cooking);
+ mes "";
+ select
+ rif(.@q == 11, l("Aww, but I was hoping to learn a recipe!")),
+ rif(.@q >= 14, l("I needed Acorn Flour.")),
+ rif(.@q >= 14, l("Do you need acorn flour yourself?")),
+ rif(.@q >= 14, l("I want to cook!")),
+ l("=(");
+ mes "";
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("What? Get out of here you noob. The recipes are the pride of this inn-bakery and I'm not going to give them away just because you asked.");
+ next;
+ mesn;
+ mesq l("Besides, I already have an apprentice - He should be cleaning the basement at this moment, including.");
+ next;
+ mesn;
+ mesq l("Get out of my face and don't say that again.");
+ setq1 General_Cooking, 12;
+ break;
+ case 2:
+ mesn;
+ mesq l("Only the best %s can make fine recipes.", getitemlink(AcornFlour));
+ next;
+ mesn;
+ mesq l("I'm willing to make you one flour for each %d %s you bring me. Three for you, and two as commission.", 5, getitemlink(Acorn));
+ next;
+ mesn;
+ mesq l("So, how many do you want?");
+ menuint
+ rif(countitem(Acorn) >= 5, l("I want %d", 1)), 1,
+ rif(countitem(Acorn) >= 25, l("I want %d", 5)), 5,
+ rif(countitem(Acorn) >= 50, l("I want %d", 10)), 10,
+ rif(countitem(Acorn) >= 125, l("I want %d", 25)), 25,
+ rif(countitem(Acorn) >= 250, l("I want %d", 50)), 50,
+ rif(countitem(Acorn) >= 500, l("I want %d", 100)), 100,
+ rif(countitem(Acorn) >= 5, l("As many as you can.")), countitem(Acorn)/5,
+ l("Ehrm, none, thanks."), 0;
+ mes "";
+ if (!@menuret)
+ break;
+ inventoryplace AcornFlour, @menuret;
+ delitem Acorn, @menuret*5;
+ getitem AcornFlour, @menuret;
+ mesn;
+ mesq l("Here you go. A pleasure doing business with you.");
+ break;
+ case 3:
+ // DailyQuest(lvl, cost, count, item)
+ DailyQuest(20, 3, 1, AcornFlour);
+ break;
+ case 4:
+ mesn;
+ mesq l("My charge is %d E per batch.", .price);
+ if (Zeny < .price)
+ break;
+ next;
+ do
+ {
+ mes "##B" + l("Drag and drop the items from your inventory in the frames.") + "##b";
+
+ // Crafting skin with 4 columns
+ setskin "craft4";
+ .@var$ = requestcraft(4); // Limit: 4 items
+ .@craft = initcraft(.@var$);
+ .@entry = findcraftentry(.@craft, CRAFT_COOKING);
+ setskin "";
+
+ // Does the recipe exist and is a sandwich?
+ if (.@entry < 0)
+ {
+ narrator
+ l("You don't know how any recipe with that."),
+ l("Do you want to try again?");
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ else
+ {
+ // Did player cheat? If not, proceed with the craft
+ if (!validatecraft(.@craft))
+ {
+ narrator
+ l("Where are the ingredients?");
+ .@tryAgain=true;
+ }
+ else
+ {
+ // Even if the recipe is right, if you don't have it on your
+ // recipe book, it should be deemed invalid.
+ if (RECIPES[.@entry])
+ {
+ usecraft .@craft;
+ narrator
+ l("Done!"),
+ l("Do you want to try again?");
+ }
+ else
+ {
+ narrator
+ l("You don't know how any recipe with that."),
+ l("Do you want to try again?");
+ }
+
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ }
+
+ // Clear unused variables and clear the screen.
+ deletecraft .@craft;
+ Zeny-=.price;
+ if (Zeny < .price)
+ .@tryAgain = false;
+ clear;
+ } while (.@tryAgain);
+ break;
+ }
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ .price = 120;
+ end;
+}
diff --git a/npc/020-2-21/_import.txt b/npc/020-2-21/_import.txt
new file mode 100644
index 00000000..99dcb741
--- /dev/null
+++ b/npc/020-2-21/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-21: Queer Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-21/_warps.txt",
diff --git a/npc/020-2-21/_warps.txt b/npc/020-2-21/_warps.txt
new file mode 100644
index 00000000..00ea811f
--- /dev/null
+++ b/npc/020-2-21/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-21: Queer Hut warps
+020-2-21,40,27,0 warp #020-2-21_40_27 0,0,020-1,161,147
diff --git a/npc/020-2-22/_import.txt b/npc/020-2-22/_import.txt
new file mode 100644
index 00000000..dec610b2
--- /dev/null
+++ b/npc/020-2-22/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-22: Residence
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-22/_warps.txt",
diff --git a/npc/020-2-22/_warps.txt b/npc/020-2-22/_warps.txt
new file mode 100644
index 00000000..944911c8
--- /dev/null
+++ b/npc/020-2-22/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-22: Residence warps
+020-2-22,42,33,0 warp #020-2-22_42_33 0,0,020-1,153,132
+020-2-22,33,24,0 warp #020-2-22_33_24 0,0,020-2-25,32,24
+020-2-22,51,24,0 warp #020-2-22_51_24 0,0,020-2-25,42,24
diff --git a/npc/020-2-23/_import.txt b/npc/020-2-23/_import.txt
new file mode 100644
index 00000000..bf53aaa9
--- /dev/null
+++ b/npc/020-2-23/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-23: Brotherhood Inn First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-23/_warps.txt",
diff --git a/npc/020-2-23/_warps.txt b/npc/020-2-23/_warps.txt
new file mode 100644
index 00000000..e1f1e502
--- /dev/null
+++ b/npc/020-2-23/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-23: Brotherhood Inn First Floor warps
+020-2-23,33,29,0 warp #020-2-23_33_29 1,0,020-1,163,73
+020-2-23,38,24,0 warp #020-2-23_38_24 0,0,020-2-3,46,26
diff --git a/npc/020-2-24/_import.txt b/npc/020-2-24/_import.txt
new file mode 100644
index 00000000..b4fa1e73
--- /dev/null
+++ b/npc/020-2-24/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-24: Tulimshar Inn First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-24/_warps.txt",
+"npc/020-2-24/kylian.txt",
diff --git a/npc/020-2-24/_warps.txt b/npc/020-2-24/_warps.txt
new file mode 100644
index 00000000..619469f5
--- /dev/null
+++ b/npc/020-2-24/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-24: Tulimshar Inn First Floor warps
+020-2-24,33,29,0 warp #020-2-24_33_29 1,0,020-1,194,163
+020-2-24,31,24,0 warp #020-2-24_31_24 0,0,020-2-20,33,23
diff --git a/npc/020-2-24/kylian.txt b/npc/020-2-24/kylian.txt
new file mode 100644
index 00000000..0b1bce37
--- /dev/null
+++ b/npc/020-2-24/kylian.txt
@@ -0,0 +1,130 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Rich merchant
+// Variables:
+// TonoriQuest_Kylian
+// q1 - State of the Quest
+// q2 - "Know" mask
+// q3 - Timer to return
+
+020-2-24,35,24,0 script Kylian NPC_KPG_MANAGER,{
+ function kylianLuggage;
+ function kylianGiveLuggage;
+ function kylianLicense;
+ .@q=getq(TonoriQuest_Kylian);
+ switch (.@q) {
+ case 0:
+ kylianLuggage();
+ break;
+ case 1:
+ mesn;
+ mesq l("Please show Adrian the luggage ticket I gave you.");
+ break;
+ case 2:
+ kylianGiveLuggage();
+ break;
+ case 3:
+ kylianLicense();
+ break;
+ default:
+ mesn;
+ mesq l("I wish to take a nap now, so please do not disturb me.");
+ break;
+ }
+ close;
+
+function kylianLuggage {
+ // Insert lore babbling here
+ mesn;
+ mesq l("Ah! Are you the room service? I have some requests.");
+ next;
+ select
+ l("Sure... What can I do for you?"),
+ l("No, I'm not!");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Too bad. Would you be interested in earning some quick money with some errands regardless?");
+ next;
+ select
+ l("I'm a great adventurer! I don't do petty errands."),
+ l("No. I'm busy."),
+ l("Well... OK.");
+ mes "";
+ if (@menu != 3)
+ return;
+ }
+ mesn;
+ mesq l("I need you to get my luggage from the docks. Just show this paper to the sailor who's watching the luggage.");
+ mesc l("%s gives you his ticket, which you promptly store in a safe pocket outside of your inventory.", .name$);
+ setq1 TonoriQuest_Kylian, 1;
+ next;
+ mesn;
+ mesq l("I'll be waiting your return.");
+ return;
+}
+
+function kylianGiveLuggage {
+ if (!countitem(Suitcase)) {
+ mesn;
+ mesq l("Please come back with my %s.", getitemlink(Suitcase));
+ return;
+ }
+ mesn;
+ mesq l("Did you get my luggage from the docks?");
+ select
+ l("Here it is."),
+ l("Don't worry; I'm on my way.");
+ mes "";
+ if (@menu == 2)
+ return;
+ delitem Suitcase, 1;
+ quest_gp(.maxLevel, 100);
+ quest_item(.maxLevel, Acorn, 12);
+ setq1 TonoriQuest_Kylian, 3;
+ mesn;
+ mesq l("Ah! Very good. I have some urgent paperwork that I've been needing to attend to.");
+ next;
+ mesn;
+ mesq l("Before you go, I also happen to have some acorns left over from my trip. You can have them if you wish; they're rather tasty.");
+ mesc l("He gives you some money and acorns.");
+ next;
+ mesn;
+ mesq l("If, however, you don't like them, you could take them to the %s. I heard they use them to make a special kind of flour.", b(l("Tulimshar bakery")));
+ next;
+ kylianLicense();
+ return;
+}
+
+function kylianLicense {
+ mesn;
+ mesq l("I'm a merchant and came to Tulimshar because I'm thinking about establishing a shop here.");
+ next;
+ mesn;
+ mesq l("While I'm going through my papers, could you find out whom I have to talk to about opening up a shop in this city?");
+ if (!(getq2(TonoriQuest_Kylian) & KYLIAN_YANIS))
+ return;
+ next;
+ select
+ l("You need to go and talk to Yanis in the government building."),
+ l("I'll see what I can do.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesc l("You explain Kylian how to reach the Townhall.");
+ next;
+ quest_gp(.maxLevel, 50);
+ setq1 TonoriQuest_Kylian, 4;
+ setq3 TonoriQuest_Kylian, gettimetick(2)+900; // 15 minutes
+ mesn;
+ mesq l("Ah... excellent! That's very helpful. I need to prepare my papers now. I might have some more questions later on though.");
+ return;
+}
+
+OnInit:
+ .maxLevel = 35;
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-25/_import.txt b/npc/020-2-25/_import.txt
new file mode 100644
index 00000000..c6d2cf19
--- /dev/null
+++ b/npc/020-2-25/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-25: Residence First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-25/_warps.txt",
diff --git a/npc/020-2-25/_warps.txt b/npc/020-2-25/_warps.txt
new file mode 100644
index 00000000..878a7b7d
--- /dev/null
+++ b/npc/020-2-25/_warps.txt
@@ -0,0 +1,6 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-25: Residence First Floor warps
+020-2-25,33,29,0 warp #020-2-25_33_29 1,0,020-1,149,129
+020-2-25,31,24,0 warp #020-2-25_31_24 0,0,020-2-22,33,25
+020-2-25,43,24,0 warp #020-2-25_43_24 0,0,020-2-22,51,25
+020-2-25,42,29,0 warp #020-2-25_42_29 1,0,020-1,157,129
diff --git a/npc/020-2-26/_import.txt b/npc/020-2-26/_import.txt
new file mode 100644
index 00000000..bf3dda11
--- /dev/null
+++ b/npc/020-2-26/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-26: Magic Academy Ground Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-26/_warps.txt",
+"npc/020-2-26/receptionist.txt",
diff --git a/npc/020-2-26/_warps.txt b/npc/020-2-26/_warps.txt
new file mode 100644
index 00000000..b9ad76db
--- /dev/null
+++ b/npc/020-2-26/_warps.txt
@@ -0,0 +1,9 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-26: Magic Academy Ground Floor warps
+020-2-26,44,42,0 warp #020-2-26_44_42 0,0,020-1,49,116
+020-2-26,34,49,0 warp #020-2-26_34_49 0,0,020-1,41,119
+020-2-26,58,46,0 warp #020-2-26_58_46 1,0,020-1,58,118
+020-2-26,71,44,0 warp #020-2-26_71_44 0,0,020-1,67,117
+020-2-26,53,27,0 warp #020-2-26_53_27 1,0,020-2-27,33,26
+020-2-26,76,33,0 warp #020-2-26_76_33 0,2,020-2-29,34,25
+020-2-26,32,37,0 warp #020-2-26_32_37 0,2,020-2-30,43,21
diff --git a/npc/020-2-26/receptionist.txt b/npc/020-2-26/receptionist.txt
new file mode 100644
index 00000000..f177d5f3
--- /dev/null
+++ b/npc/020-2-26/receptionist.txt
@@ -0,0 +1,21 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Receptionist in Magic Academy.
+// THIS IS A PLACEHOLDER!
+
+020-2-26,59,32,0 script Receptionist NPC_REBECCA,{
+ speech
+ l("Hi!"),
+ l("This is the magic academy. If all those mages were not so absentminded, they could make some furniture."),
+ l("But oh well, people have different priorities it seems. Ask Micksha.");
+ // if (something) ask about enrolling - Hocus Quest
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+
diff --git a/npc/020-2-27/_import.txt b/npc/020-2-27/_import.txt
new file mode 100644
index 00000000..527b9e60
--- /dev/null
+++ b/npc/020-2-27/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-27: Magic Acedemy Central, First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-27/_warps.txt",
diff --git a/npc/020-2-27/_warps.txt b/npc/020-2-27/_warps.txt
new file mode 100644
index 00000000..5654eb94
--- /dev/null
+++ b/npc/020-2-27/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-27: Magic Acedemy Central, First Floor warps
+020-2-27,33,27,0 warp #020-2-27_33_27 2,0,020-2-26,52,28
+020-2-27,46,22,0 warp #020-2-27_46_22 2,0,020-2-28,42,22
diff --git a/npc/020-2-28/_import.txt b/npc/020-2-28/_import.txt
new file mode 100644
index 00000000..cbdcd407
--- /dev/null
+++ b/npc/020-2-28/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-28: Magic Acedemy Central, Second Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-28/_warps.txt",
+"npc/020-2-28/pauline.txt",
diff --git a/npc/020-2-28/_warps.txt b/npc/020-2-28/_warps.txt
new file mode 100644
index 00000000..bb588fb5
--- /dev/null
+++ b/npc/020-2-28/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-28: Magic Acedemy Central, Second Floor warps
+020-2-28,43,23,0 warp #020-2-28_43_23 2,0,020-2-27,46,24
+020-2-28,34,33,0 warp #020-2-28_34_33 0,0,020-1,56,108
+020-2-28,42,33,0 warp #020-2-28_42_33 0,0,020-1,60,108
diff --git a/npc/020-2-28/pauline.txt b/npc/020-2-28/pauline.txt
new file mode 100644
index 00000000..72b47959
--- /dev/null
+++ b/npc/020-2-28/pauline.txt
@@ -0,0 +1,39 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Pauline, the War Mage.
+// THIS IS A PLACEHOLDER!
+
+020-2-28,36,20,0 script Pauline NPC_PAULINE,{
+ speech
+ l("Hi!"),
+ l("Should I tell you the secret of a good fight?"),
+ l("CONFRONT AND DESTROY!! (Don't tell your parents I said that.");
+ select
+ l("You're weird, I have to go sorry."),
+ l("I can't do that, I keep getting killed.");
+ mes "";
+ if (@menu == 1)
+ close;
+ mesn;
+ mesq l("Oh no! Well, I never said to confront alone. Did you try going with friends?");
+ next;
+ if (askyesno() == ASK_NO) {
+ mesn;
+ mesq l("Then you should do that. It is always more fun with friends.");
+ close;
+ }
+ mesn;
+ mesq l("Ah... Then maybe you should summon a monster to your aid, or hire a mercenary.");
+ next;
+ mesn;
+ mesq l("Hold tight. Hire a mercenary? That was not in the script. Please call Jesusalva ASAP.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
+
diff --git a/npc/020-2-29/_import.txt b/npc/020-2-29/_import.txt
new file mode 100644
index 00000000..f6d5a319
--- /dev/null
+++ b/npc/020-2-29/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-29: Magic Acedemy East, First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-29/_warps.txt",
diff --git a/npc/020-2-29/_warps.txt b/npc/020-2-29/_warps.txt
new file mode 100644
index 00000000..385b2b03
--- /dev/null
+++ b/npc/020-2-29/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-29: Magic Acedemy East, First Floor warps
+020-2-29,33,25,0 warp #020-2-29_33_25 0,2,020-2-26,75,34
+020-2-29,53,34,0 warp #020-2-29_53_34 0,0,020-1,87,115
diff --git a/npc/020-2-3/_import.txt b/npc/020-2-3/_import.txt
new file mode 100644
index 00000000..12378155
--- /dev/null
+++ b/npc/020-2-3/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-3: Brotherhood Inn
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-3/_warps.txt",
+"npc/020-2-3/inac.txt",
diff --git a/npc/020-2-3/_warps.txt b/npc/020-2-3/_warps.txt
new file mode 100644
index 00000000..027b732e
--- /dev/null
+++ b/npc/020-2-3/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-3: Brotherhood Inn warps
+020-2-3,45,34,0 warp #020-2-3_45_34 0,0,020-1,166,78
+020-2-3,46,25,0 warp #020-2-3_46_25 0,0,020-2-23,37,24
diff --git a/npc/020-2-3/inac.txt b/npc/020-2-3/inac.txt
new file mode 100644
index 00000000..8966c68d
--- /dev/null
+++ b/npc/020-2-3/inac.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Inac, a Brotherhood member inside their hut.
+// THIS IS A PLACEHOLDER!
+
+020-2-3,41,26,0 script Inac NPC_RAIJIN_MALE_BROTHERHOOD,{
+ speech
+ l("Hi!"),
+ l("Can you help me? It is so dark, and smelly, in here."),
+ l("I urgently need a bottle of fresh air.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-30/_import.txt b/npc/020-2-30/_import.txt
new file mode 100644
index 00000000..97b89ffd
--- /dev/null
+++ b/npc/020-2-30/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-30: Magic Acedemy West, First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-30/_warps.txt",
+"npc/020-2-30/david.txt",
diff --git a/npc/020-2-30/_warps.txt b/npc/020-2-30/_warps.txt
new file mode 100644
index 00000000..bddd1648
--- /dev/null
+++ b/npc/020-2-30/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-30: Magic Acedemy West, First Floor warps
+020-2-30,44,21,0 warp #020-2-30_44_21 0,2,020-2-26,33,38
diff --git a/npc/020-2-30/david.txt b/npc/020-2-30/david.txt
new file mode 100644
index 00000000..03bf19f9
--- /dev/null
+++ b/npc/020-2-30/david.txt
@@ -0,0 +1,42 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// David is the head of Alchemy class in the Magic Academy
+
+020-2-30,36,24,0 script David NPC_MAGE_BLUE,{
+ function rossyPotion;
+ mesn;
+ mesq l("Hello there. I am David, head of alchemy in the magic academy.");
+ next;
+ mesn;
+ mesq l("If you are not a student, please leave the premises at once.");
+ if (getq(HurnscaldQuests_Rossy) == 8)
+ rossyPotion();
+ close;
+
+function rossyPotion {
+ next;
+ select
+ l("Alright, I'll be going."),
+ l("Actually, Rossy told me to deliver a potion to you.");
+ mes "";
+ if (@menu == 1)
+ return;
+ mesn;
+ mesq l("Ah, just in time. I asked Hocus' to send a letter; the deadline was coming up soon.");
+ next;
+ mesn;
+ mesq l("It seems okay-ish, I guess? Okay-ish is enough. Anyway, I'll analyze it and grade fairly. You can tell her that.");
+ next;
+ mesn;
+ mesq l("And unless you are a student, I'll have to ask you to leave the premises.");
+ setq HurnscaldQuests_Rossy, 9;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/020-2-31/_import.txt b/npc/020-2-31/_import.txt
new file mode 100644
index 00000000..da30659a
--- /dev/null
+++ b/npc/020-2-31/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-31: Lighthouse Ground Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-31/_warps.txt",
diff --git a/npc/020-2-31/_warps.txt b/npc/020-2-31/_warps.txt
new file mode 100644
index 00000000..b7c6e28c
--- /dev/null
+++ b/npc/020-2-31/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-31: Lighthouse Ground Floor warps
+020-2-31,36,20,0 warp #020-2-31_36_20 2,0,020-2-32,36,28
+020-2-31,34,32,0 warp #020-2-31_34_32 0,0,020-1,71,57
diff --git a/npc/020-2-32/_import.txt b/npc/020-2-32/_import.txt
new file mode 100644
index 00000000..8d34c469
--- /dev/null
+++ b/npc/020-2-32/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-32: Lighthouse First Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-32/_warps.txt",
diff --git a/npc/020-2-32/_warps.txt b/npc/020-2-32/_warps.txt
new file mode 100644
index 00000000..f66179a2
--- /dev/null
+++ b/npc/020-2-32/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-32: Lighthouse First Floor warps
+020-2-32,36,29,0 warp #020-2-32_36_29 2,0,020-2-31,36,22
+020-2-32,36,20,0 warp #020-2-32_36_20 2,0,020-2-33,36,28
diff --git a/npc/020-2-33/_import.txt b/npc/020-2-33/_import.txt
new file mode 100644
index 00000000..c65039f6
--- /dev/null
+++ b/npc/020-2-33/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-33: Lighthouse Second Floor
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-33/_warps.txt",
diff --git a/npc/020-2-33/_warps.txt b/npc/020-2-33/_warps.txt
new file mode 100644
index 00000000..4b8ce343
--- /dev/null
+++ b/npc/020-2-33/_warps.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-33: Lighthouse Second Floor warps
+020-2-33,36,29,0 warp #020-2-33_36_29 2,0,020-2-32,36,22
+020-2-33,37,21,0 warp #020-2-33_37_21 0,0,020-1,71,44
diff --git a/npc/020-2-34/_import.txt b/npc/020-2-34/_import.txt
new file mode 100644
index 00000000..2a823164
--- /dev/null
+++ b/npc/020-2-34/_import.txt
@@ -0,0 +1,5 @@
+// Map 020-2-34: Tulimshar Casino
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-34/_warps.txt",
+"npc/020-2-34/casino.txt",
+"npc/020-2-34/donutello.txt",
diff --git a/npc/020-2-34/_warps.txt b/npc/020-2-34/_warps.txt
new file mode 100644
index 00000000..2a4a162e
--- /dev/null
+++ b/npc/020-2-34/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-34: Tulimshar Casino warps
+020-2-34,37,40,0 warp #020-2-34_37_40 0,0,020-2-20,37,22
diff --git a/npc/020-2-34/casino.txt b/npc/020-2-34/casino.txt
new file mode 100644
index 00000000..06d25fc4
--- /dev/null
+++ b/npc/020-2-34/casino.txt
@@ -0,0 +1,17 @@
+// Tulimshar Inn Casino
+// Author:
+// Jesusalva
+
+020-2-34,33,22,0 duplicate(Slot Machine) Slot Machine#T1 NPC_HASAN
+
+020-2-34,45,22,0 duplicate(High Lower) Gambler#T1 NPC_HUMAN_MALE_BROTHERHOOD
+
+// Hot point for Kylian's Quest
+020-2-34,37,34,0 script #HeyCasino NPC_HIDDEN,0,0,{
+ end;
+OnTouch:
+ // TODO: "Donutello : Hey stop there! You are underlevel, you cannot enter!"
+ setq2 TonoriQuest_Kylian, getq2(TonoriQuest_Kylian) | KYLIAN_CASINO;
+ end;
+}
+
diff --git a/npc/020-2-34/donutello.txt b/npc/020-2-34/donutello.txt
new file mode 100644
index 00000000..8ff494d8
--- /dev/null
+++ b/npc/020-2-34/donutello.txt
@@ -0,0 +1,166 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Donutello is the Donut Apprentice
+
+020-2-34,33,48,0 script Donutello NPC_CHEF_LEGACY,{
+ function foodQuestline;
+
+ // Instance behavior
+ if (instance_id() > 0) {
+ npctalk3 l("Time remaining: %s" , FuzzyTime(@tinner));
+ end;
+ }
+
+ mesn;
+ mesq l("Why are you here? Only staff and VIP are supposed to go down here.");
+
+ .@q=getq(General_Cooking);
+ if (.@q > 11)
+ foodQuestline();
+
+ close;
+
+function foodQuestline {
+ .@q=getq(General_Cooking);
+ .@q2=getq2(General_Cooking);
+ mes "";
+ select
+ rif(.@q == 12, l("Can you teach me how to cook sweets?")),
+ rif(.@q == 13, l("Rattos killed. So, my recipe...")),
+ l("What is the area, anyway?"),
+ l("Erm, wrong door, sorry.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("What? But the recipes are the pride of Tulimshar Inn, and-- Oohhhh.... Maybe...");
+ next;
+ mesn;
+ mesq l("Hey, I can teach the %s recipe. However...", getitemlink(Donut));
+ next;
+ select
+ l("Oh no - I'm not your personal delivery guy! Bye bye!"),
+ l("Here we go again...");
+ mes "";
+ if (@menu == 1)
+ break;
+ mesn;
+ mesq l("I am scared of the rattos! And Riskim says that we cannot have rattos here, so he also wants me to kill them!! %%i");
+ next;
+ mesn strcharinfo(0);
+ select
+ l("Sounds cliché, but okay, I'll help."),
+ l("They're just rattos?");
+ mes "";
+ mesn;
+ mesq l("Oh, but they aren't only fast - they're more vicious than common rattos, from all the sugar they eat. And if you take too long killing them, Riskim will hear and - things will turn out badly!");
+ next;
+ mesc l("Accept quest?"), 1;
+ mesc l("Time limit: %s", l("2 minutes"));
+ .@mapn$="Tinn@"+getcharid(0);
+ if (askyesno() == ASK_NO)
+ break;
+
+ if (instanceowner(@tinnst) != getcharid(3)) {
+ @tinnst = instance_create("T.INN "+getcharid(0), getcharid(3), IOT_CHAR);
+ instance_attachmap("020-2-34", @tinnst, false, .@mapn$);
+ instance_set_timeout(120, 120, @tinnst);
+ instance_init(@tinnst);
+ } else {
+ instance_set_timeout(120, 120, @tinnst);
+ }
+ @tinner = gettimetick(2) + 120;
+ killmonsterall(.@mapn$);
+ for (.@i = 0; .@i < 4; .@i++) {
+ .@mob=areamonster(.@mapn$, 32, 50, 52, 57, strmobinfo(1, Ratto), Ratto, 1, "Donutello::OnRattoKill");
+ // Make them vicious
+ .@bhp= getunitdata(.@mob, UDT_MAXHP);
+ .@bat1=getunitdata(.@mob, UDT_ATKMIN);
+ .@bat2=getunitdata(.@mob, UDT_ATKMAX);
+ .@bhit=getunitdata(.@mob, UDT_HIT);
+ setunitdata(.@mob, UDT_MAXHP, .@bhp*22/10);
+ setunitdata(.@mob, UDT_HP, .@bhp*22/10);
+ setunitdata(.@mob, UDT_ATKMIN, .@bat1*27/10);
+ setunitdata(.@mob, UDT_ATKMAX, .@bat2*27/10);
+ setunitdata(.@mob, UDT_HIT, .@bhit*20);
+ }
+ warp .@mapn$, 37, 50;
+ dispbottom l("Time remaining: %s", FuzzyTime(@tinner));
+ closeclientdialog;
+ close;
+ break;
+ case 2:
+ mesn;
+ mesq l("Phew, thanks %s. These rattos were going to be the ruin of me!", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("However, you must bring me %d %s, %d %s and %d %s. Because the ingredients are you!",
+ 6, getitemlink(AcornFlour),
+ 2, getitemlink(MoubooMilk),
+ 2, getitemlink(ChocolateBar));
+ next;
+ mesn;
+ mesq l("Erm, Acorn Flour is made of mashed up acorns. %d Acorns make one flour. So, I'll accept the acorns instead of the flour as you helped me a lot.", 3);
+ next;
+ mesc l("Deliver the ingredients?"), 1;
+ mesf("- %d %s", 18, getitemlink(Acorn));
+ mesf("- %d %s", 2, getitemlink(MoubooMilk));
+ mesf("- %d %s", 2, getitemlink(ChocolateBar));
+ mes "";
+ if (askyesno() == ASK_NO)
+ break;
+ if (countitem(ChocolateBar) < 2 ||
+ countitem(MoubooMilk) < 2 ||
+ countitem(Acorn) < 18)
+ break;
+ inventoryplace Donut, 1;
+ delitem Acorn, 18;
+ delitem MoubooMilk, 2;
+ delitem ChocolateBar, 2;
+ setq1 General_Cooking, 14;
+ RECIPES[CraftDonut]=true;
+ getitem Donut, 1;
+ mesn;
+ mesq l("Great, thanks! If you need more flour you can ask Riskim. He also buys flour for a good price.");
+ next;
+ mesn;
+ mesq l("First divide the ingredients on two halves. Take the first half, mix them, bring the oven, and blablablablah....");
+ next;
+ mesn;
+ mesq l("And after a while, you have %s! I made two with the ingredients you gave me, one for you and one for me. This is my thankyou for helping me out on the storeroom. Enjoy!", getitemlink(Donut));
+ break;
+ case 3:
+ mesn;
+ mesq l("Up there is the Casino. Erm, it is totally legal, I swear.");
+ next;
+ mesn;
+ mesq l("Here is the storeroom, and... Hey! I don't need to answer you questions!!");
+ break;
+ }
+ return;
+
+OnRattoKill:
+ if (!playerattached()) end;
+ // FIXME - Make sure this is an instanced map
+ //if (instance_id() < 1) end;
+
+ if (mobcount(getmap(), "Donutello::OnRattoKill") <= 0) {
+ dispbottom l("I'm done with this.");
+ getmapxy(.@m$, .@x, .@y, 0);
+ setq1 General_Cooking, 13;
+ sleep2(1000); // Give you some time to loot
+ warp "020-2-34", .@x, .@y;
+ sleep2(500); // Give M+ some time to re-render everything
+ npctalk3 l("Thanks %s... I feel much safer now!", strcharinfo(0));
+ } else {
+ dispbottom l("Rattos remaining: %d", mobcount(getmap(), "Donutello::OnRattoKill"));
+ }
+ end;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-4/_import.txt b/npc/020-2-4/_import.txt
new file mode 100644
index 00000000..5ff8744a
--- /dev/null
+++ b/npc/020-2-4/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-4: Brotherhood Hut
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-4/_warps.txt",
diff --git a/npc/020-2-4/_warps.txt b/npc/020-2-4/_warps.txt
new file mode 100644
index 00000000..1a32b934
--- /dev/null
+++ b/npc/020-2-4/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-4: Brotherhood Hut warps
+020-2-4,35,29,0 warp #020-2-4_35_29 0,0,020-1,179,99
diff --git a/npc/020-2-5/_import.txt b/npc/020-2-5/_import.txt
new file mode 100644
index 00000000..e7e9087c
--- /dev/null
+++ b/npc/020-2-5/_import.txt
@@ -0,0 +1,5 @@
+// Map 020-2-5: Legion Castle
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-5/_warps.txt",
+"npc/020-2-5/dausen.txt",
+"npc/020-2-5/filipa.txt",
diff --git a/npc/020-2-5/_warps.txt b/npc/020-2-5/_warps.txt
new file mode 100644
index 00000000..de006eac
--- /dev/null
+++ b/npc/020-2-5/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-5: Legion Castle warps
+020-2-5,34,31,0 warp #020-2-5_34_31 0,0,020-1,281,86
+020-2-5,45,38,0 warp #020-2-5_45_38 0,0,020-1,291,89
+020-2-5,46,21,0 warp #020-2-5_46_21 2,0,020-2-6,36,28
diff --git a/npc/020-2-5/dausen.txt b/npc/020-2-5/dausen.txt
new file mode 100644
index 00000000..1354b636
--- /dev/null
+++ b/npc/020-2-5/dausen.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Dausen, the Legion Lieutenant inside Legion HQ in Tulim.
+// THIS IS A PLACEHOLDER!
+
+020-2-5,40,23,0 script Dausen NPC_HUMAN_MALE_CHIEF_ARTIS_LEGION,{
+ speech
+ l("Hi there. I am lieutenant Dausen."),
+ l("Red Sands desert is dangerous at the moment, so we sealed it off."),
+ l("The mines are also on the risk of collapsing, so the workers had to be evacuated as well."),
+ l("I fear for the future of this town...");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-5/filipa.txt b/npc/020-2-5/filipa.txt
new file mode 100644
index 00000000..cbdd40e5
--- /dev/null
+++ b/npc/020-2-5/filipa.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Filipa, a Legion Guard inside Legion HQ in Tulim.
+// THIS IS A PLACEHOLDER!
+
+020-2-5,47,28,0 script Filipa NPC_RAIJIN_FEMALE_LEGION_ARTIS,{
+ speech
+ l("Hi there."),
+ l("This is no place for you, get moving!"),
+ l("If you want, you can hunt something, or cook something, or craft something."),
+ l("Whatever, just get out of here already!");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-6/_import.txt b/npc/020-2-6/_import.txt
new file mode 100644
index 00000000..82764d38
--- /dev/null
+++ b/npc/020-2-6/_import.txt
@@ -0,0 +1,3 @@
+// Map 020-2-6: Legion Tower
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-6/_warps.txt",
diff --git a/npc/020-2-6/_warps.txt b/npc/020-2-6/_warps.txt
new file mode 100644
index 00000000..90ae3308
--- /dev/null
+++ b/npc/020-2-6/_warps.txt
@@ -0,0 +1,5 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-6: Legion Tower warps
+020-2-6,36,29,0 warp #020-2-6_36_29 2,0,020-2-5,46,22
+020-2-6,37,21,0 warp #020-2-6_37_21 0,0,020-1,289,72
+020-2-6,31,30,0 warp #020-2-6_31_30 0,0,020-1,289,81
diff --git a/npc/020-2-7/_import.txt b/npc/020-2-7/_import.txt
new file mode 100644
index 00000000..b4179bc5
--- /dev/null
+++ b/npc/020-2-7/_import.txt
@@ -0,0 +1,4 @@
+// Map 020-2-7: Legion Guardhouse
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-7/_warps.txt",
+"npc/020-2-7/manoli.txt",
diff --git a/npc/020-2-7/_warps.txt b/npc/020-2-7/_warps.txt
new file mode 100644
index 00000000..c008e51d
--- /dev/null
+++ b/npc/020-2-7/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-7: Legion Guardhouse warps
+020-2-7,35,33,0 warp #020-2-7_35_33 0,0,020-1,293,107
diff --git a/npc/020-2-7/manoli.txt b/npc/020-2-7/manoli.txt
new file mode 100644
index 00000000..578f0569
--- /dev/null
+++ b/npc/020-2-7/manoli.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Manoli, a Legion Guard inside the Legion storage building.
+// THIS IS A PLACEHOLDER!
+
+020-2-7,35,23,0 script Manoli NPC_HUMAN_FEMALE_LEGION_ARTIS,{
+ speech
+ l("Hi there."),
+ l("Looks like someone ran out of ideas for placeholder NPCs."),
+ l("So if you want, you can hunt something, or cook something, or craft somethig."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-8/_import.txt b/npc/020-2-8/_import.txt
new file mode 100644
index 00000000..d7122dcb
--- /dev/null
+++ b/npc/020-2-8/_import.txt
@@ -0,0 +1,5 @@
+// Map 020-2-8: Tulimshar Blacksmith
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-8/_warps.txt",
+"npc/020-2-8/heathin.txt",
+"npc/020-2-8/jhedia.txt",
diff --git a/npc/020-2-8/_warps.txt b/npc/020-2-8/_warps.txt
new file mode 100644
index 00000000..1a0eaf03
--- /dev/null
+++ b/npc/020-2-8/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-8: Tulimshar Blacksmith warps
+020-2-8,35,33,0 warp #020-2-8_35_33 0,0,020-1,292,131
diff --git a/npc/020-2-8/heathin.txt b/npc/020-2-8/heathin.txt
new file mode 100644
index 00000000..4880313e
--- /dev/null
+++ b/npc/020-2-8/heathin.txt
@@ -0,0 +1,19 @@
+// Evol scripts.
+// Author:
+// Micksha
+// Description:
+// Heathin, Tulimshar's smith.
+// THIS IS A PLACEHOLDER!
+
+020-2-8,36,23,0 script Heathin NPC_ANGUS_THE_SMITH,{
+ speech
+ l("Hi there."),
+ l("Looks like someone ran out of ideas for placeholder NPCs."),
+ l("So if you want, you can bring me a hammer."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 2;
+ end;
+}
diff --git a/npc/020-2-8/jhedia.txt b/npc/020-2-8/jhedia.txt
new file mode 100644
index 00000000..ee412001
--- /dev/null
+++ b/npc/020-2-8/jhedia.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Jhedia, Apprentice of Tulimshar's smith Heathin.
+// THIS IS A PLACEHOLDER!
+
+020-2-8,42,24,0 script Jhedia NPC_YOUNG_MAN_IN_PINK,{
+ speech
+ l("Hi there."),
+ l("Looks like someone ran out of ideas for placeholder NPCs."),
+ l("So if you want, you can bring Heathin a hammer."),
+ l("Whatever.");
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/020-2-9/_import.txt b/npc/020-2-9/_import.txt
new file mode 100644
index 00000000..bd0771e3
--- /dev/null
+++ b/npc/020-2-9/_import.txt
@@ -0,0 +1,5 @@
+// Map 020-2-9: Tulimshar Townhall
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/020-2-9/_warps.txt",
+"npc/020-2-9/hydusun.txt",
+"npc/020-2-9/yanis.txt",
diff --git a/npc/020-2-9/_warps.txt b/npc/020-2-9/_warps.txt
new file mode 100644
index 00000000..d9a8afc5
--- /dev/null
+++ b/npc/020-2-9/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 020-2-9: Tulimshar Townhall warps
+020-2-9,44,37,0 warp #020-2-9_44_37 0,0,020-1,280,141
diff --git a/npc/020-2-9/hydusun.txt b/npc/020-2-9/hydusun.txt
new file mode 100644
index 00000000..c4f55b92
--- /dev/null
+++ b/npc/020-2-9/hydusun.txt
@@ -0,0 +1,62 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Hydusun the Tulimshar storage guy.
+// THIS IS A PLACEHOLDER!
+
+020-2-9,35,25,0 script Hydusun NPC_RICHARD_LEGACY,{
+ // Storage/Banking function not unlocked in Artis
+ if (!getq(ArtisQuests_Lloyd)) {
+ speech
+ l("Oh hey!"),
+ l("I was supposed to act as storagekeeper, but I forgot my key."),
+ l("Come back later, perhaps I can find it.");
+ close;
+ }
+ mesn;
+ mesq l("Welcome to %s's Bank!", l($@BANK_TOWN$[.bankid]));
+ next;
+
+ do
+ {
+ select
+ l("I would like to store some items."),
+ l("I would like to perform money transactions."),
+ l("Is there any request for me?"),
+ menuaction(l("Quit"));
+
+ mes "";
+
+ switch (@menu) {
+ case 1:
+ mesn;
+ mesq l("Sure thing! I'll have your items transported here from Artis before you realize!");
+ next;
+ closeclientdialog();
+ openstorage();
+ close;
+ case 2:
+ MerchantGuild_Bank();
+ break;
+ case 3:
+ MerchantGuild_Quests(.bankid);
+ break;
+ default:
+ closeclientdialog;
+ goodbye;
+ close;
+ }
+
+ } while (true);
+ close;
+
+OnInit:
+ .distance = 4;
+
+ // Bank configuration
+ array_push($@BANK_NAME$, .name$);
+ array_push($@BANK_TOWN$, "Tulimshar");
+ .bankid = getarraysize($@BANK_NAME$)-1;
+ end;
+}
diff --git a/npc/020-2-9/yanis.txt b/npc/020-2-9/yanis.txt
new file mode 100644
index 00000000..d5c8ea53
--- /dev/null
+++ b/npc/020-2-9/yanis.txt
@@ -0,0 +1,18 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Yanis, town bureaucrat
+// THIS IS A PLACEHOLDER!
+
+020-2-9,44,27,0 script Yanis NPC_ELVEN_MAN_STANDING,{
+ setq2 TonoriQuest_Kylian, getq2(TonoriQuest_Kylian) | KYLIAN_YANIS;
+ mesn;
+ mesq l("Welcome. I'm handling issues with trading licenses for the shop owners in Tulimshar. Can I help you?");
+ // TODO: Livio and mifristcher are working here so I'll not write this script.
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/_anchors.txt b/npc/_anchors.txt
new file mode 100644
index 00000000..a1421cdb
--- /dev/null
+++ b/npc/_anchors.txt
@@ -0,0 +1,53 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+
+- script __anchors__ 32767,{
+OnInit:
+ .ht = htnew();
+ htput(.ht, "^ALCH", "001-2-26 32 40");
+ htput(.ht, "^ALIG|^HID", "000-2-4 36 30");
+ htput(.ht, "^ART", "001-1 89 86");
+ htput(.ht, "^ASPH|MOOR", "009-1 53 171");
+ htput(.ht, "^BLACK|SMITH", "001-2-27 35 32");
+ htput(.ht, "^BOT|CHECK", "botcheck 30 30");
+ htput(.ht, "^CAMP|FIRE", "008-1 55 46");
+ htput(.ht, "^CANDOR", "012-1 49 114");
+ htput(.ht, "^CHAP", "009-1 212 151");
+ htput(.ht, "^CITY|^HALL", "001-2-7 36 41");
+ htput(.ht, "^DIMOND|COVE", "008-1 106 222");
+ htput(.ht, "^DRA|ISLAND", "000-1 62 111");
+ htput(.ht, "^FARM|MOUB", "008-1 71 129");
+ htput(.ht, "^FERMI|VOTE", "fermi 29 20");
+ htput(.ht, "^FIRST|^DECK1?$", "000-2-0 23 28");
+ htput(.ht, "^GARDEN", "020-1 76 99");
+ htput(.ht, "^HARB|^MASTER", "001-2-16 28 32");
+ htput(.ht, "^HOLD$", "000-2-2 42 31");
+ htput(.ht, "^HURN", "008-1 250 109");
+ htput(.ht, "^LAVA", "008-3-0 35 28");
+ htput(.ht, "^LEG", "001-2-33 34 42");
+ htput(.ht, "^LIB", "001-2-4 42 35");
+ htput(.ht, "^LIGHT", "001-2-0 37 32");
+ htput(.ht, "^LUVIA", "008-1 256 206");
+ htput(.ht, "^MAGIC|ACAD", "020-1 51 119");
+ htput(.ht, "^MERCH|^BANK", "001-2-19 28 30");
+ htput(.ht, "^MIGGLE|SOREN", "009-1 174 95");
+ htput(.ht, "^MINE", "020-1 76 237");
+ htput(.ht, "^MOON", "001-2-2 40 34");
+ htput(.ht, "^NARD", "000-2-3 21 28");
+ htput(.ht, "^NOBLE1?$", "001-2-1 37 37");
+ htput(.ht, "^NOBLE2$", "001-2-10 40 37");
+ htput(.ht, "^NOBLE3$", "001-2-11 45 33");
+ htput(.ht, "^NOBLE4$", "001-2-12 34 32");
+ htput(.ht, "^NOBLE5$", "001-2-15 34 38");
+ htput(.ht, "^OASIS", "020-1 287 246");
+ htput(.ht, "^RED|PLUSH|^INN", "001-2-28 30 35");
+ htput(.ht, "^ROSSY", "008-1 49 158");
+ htput(.ht, "^SECOND|^DECK2$", "000-2-1 67 32");
+ htput(.ht, "^SHIP2$", "001-2-21 23 28");
+ htput(.ht, "^START2$", "000-0-0 26 28");
+ htput(.ht, "^START3$", "000-0-1 26 28");
+ htput(.ht, "^START|^BEGIN", "000-0 22 24");
+ htput(.ht, "^TULIM|MARKET", "020-1 224 175");
+ htput(.ht, "^VEIN", "008-3-0 87 172");
+ htput(.ht, "^WARE", "001-2-18 37 31");
+ htput(.ht, "^WEST|PORT", "008-1-1 52 60");
+}
diff --git a/npc/_import.txt b/npc/_import.txt
new file mode 100644
index 00000000..65890740
--- /dev/null
+++ b/npc/_import.txt
@@ -0,0 +1,176 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+
+@include "npc/000-0-0/_import.txt"
+@include "npc/000-0-1/_import.txt"
+@include "npc/000-0/_import.txt"
+@include "npc/000-1/_import.txt"
+@include "npc/000-2-0/_import.txt"
+@include "npc/000-2-1/_import.txt"
+@include "npc/000-2-2/_import.txt"
+@include "npc/000-2-3/_import.txt"
+@include "npc/000-2-4/_import.txt"
+@include "npc/001-1/_import.txt"
+@include "npc/001-2-0/_import.txt"
+@include "npc/001-2-1/_import.txt"
+@include "npc/001-2-10/_import.txt"
+@include "npc/001-2-11/_import.txt"
+@include "npc/001-2-12/_import.txt"
+@include "npc/001-2-13/_import.txt"
+@include "npc/001-2-14/_import.txt"
+@include "npc/001-2-15/_import.txt"
+@include "npc/001-2-16/_import.txt"
+@include "npc/001-2-17/_import.txt"
+@include "npc/001-2-18/_import.txt"
+@include "npc/001-2-19/_import.txt"
+@include "npc/001-2-2/_import.txt"
+@include "npc/001-2-20/_import.txt"
+@include "npc/001-2-21/_import.txt"
+@include "npc/001-2-22/_import.txt"
+@include "npc/001-2-23/_import.txt"
+@include "npc/001-2-24/_import.txt"
+@include "npc/001-2-25/_import.txt"
+@include "npc/001-2-26/_import.txt"
+@include "npc/001-2-27/_import.txt"
+@include "npc/001-2-28/_import.txt"
+@include "npc/001-2-29/_import.txt"
+@include "npc/001-2-3/_import.txt"
+@include "npc/001-2-30/_import.txt"
+@include "npc/001-2-31/_import.txt"
+@include "npc/001-2-32/_import.txt"
+@include "npc/001-2-33/_import.txt"
+@include "npc/001-2-34/_import.txt"
+@include "npc/001-2-35/_import.txt"
+@include "npc/001-2-36/_import.txt"
+@include "npc/001-2-37/_import.txt"
+@include "npc/001-2-38/_import.txt"
+@include "npc/001-2-39/_import.txt"
+@include "npc/001-2-4/_import.txt"
+@include "npc/001-2-40/_import.txt"
+@include "npc/001-2-41/_import.txt"
+@include "npc/001-2-42/_import.txt"
+@include "npc/001-2-43/_import.txt"
+@include "npc/001-2-5/_import.txt"
+@include "npc/001-2-6/_import.txt"
+@include "npc/001-2-7/_import.txt"
+@include "npc/001-2-8/_import.txt"
+@include "npc/001-2-9/_import.txt"
+@include "npc/001-3-0/_import.txt"
+@include "npc/001-3-1/_import.txt"
+@include "npc/001-3-2/_import.txt"
+@include "npc/008-1-1/_import.txt"
+@include "npc/008-1/_import.txt"
+@include "npc/008-2-0/_import.txt"
+@include "npc/008-2-1/_import.txt"
+@include "npc/008-2-10/_import.txt"
+@include "npc/008-2-11/_import.txt"
+@include "npc/008-2-12/_import.txt"
+@include "npc/008-2-13/_import.txt"
+@include "npc/008-2-14/_import.txt"
+@include "npc/008-2-15/_import.txt"
+@include "npc/008-2-16/_import.txt"
+@include "npc/008-2-17/_import.txt"
+@include "npc/008-2-18/_import.txt"
+@include "npc/008-2-19/_import.txt"
+@include "npc/008-2-2/_import.txt"
+@include "npc/008-2-20/_import.txt"
+@include "npc/008-2-21/_import.txt"
+@include "npc/008-2-22/_import.txt"
+@include "npc/008-2-23/_import.txt"
+@include "npc/008-2-24/_import.txt"
+@include "npc/008-2-25/_import.txt"
+@include "npc/008-2-26/_import.txt"
+@include "npc/008-2-27/_import.txt"
+@include "npc/008-2-28/_import.txt"
+@include "npc/008-2-29/_import.txt"
+@include "npc/008-2-3/_import.txt"
+@include "npc/008-2-30/_import.txt"
+@include "npc/008-2-31/_import.txt"
+@include "npc/008-2-32/_import.txt"
+@include "npc/008-2-4/_import.txt"
+@include "npc/008-2-5/_import.txt"
+@include "npc/008-2-6/_import.txt"
+@include "npc/008-2-7/_import.txt"
+@include "npc/008-2-8/_import.txt"
+@include "npc/008-2-9/_import.txt"
+@include "npc/008-3-0/_import.txt"
+@include "npc/008-3-1/_import.txt"
+@include "npc/008-3-2/_import.txt"
+@include "npc/008-3-3/_import.txt"
+@include "npc/008-3-4/_import.txt"
+@include "npc/008-3-5/_import.txt"
+@include "npc/008-3-6/_import.txt"
+@include "npc/009-1/_import.txt"
+@include "npc/009-2-0/_import.txt"
+@include "npc/009-2-1/_import.txt"
+@include "npc/009-2-10/_import.txt"
+@include "npc/009-2-11/_import.txt"
+@include "npc/009-2-12/_import.txt"
+@include "npc/009-2-13/_import.txt"
+@include "npc/009-2-14/_import.txt"
+@include "npc/009-2-15/_import.txt"
+@include "npc/009-2-16/_import.txt"
+@include "npc/009-2-17/_import.txt"
+@include "npc/009-2-18/_import.txt"
+@include "npc/009-2-2/_import.txt"
+@include "npc/009-2-3/_import.txt"
+@include "npc/009-2-4/_import.txt"
+@include "npc/009-2-5/_import.txt"
+@include "npc/009-2-6/_import.txt"
+@include "npc/009-2-7/_import.txt"
+@include "npc/009-2-8/_import.txt"
+@include "npc/009-2-9/_import.txt"
+@include "npc/012-1/_import.txt"
+@include "npc/012-2-1/_import.txt"
+@include "npc/012-2-2/_import.txt"
+@include "npc/012-2-3/_import.txt"
+@include "npc/012-2-4/_import.txt"
+@include "npc/012-2-5/_import.txt"
+@include "npc/012-2-6/_import.txt"
+@include "npc/012-2-7/_import.txt"
+@include "npc/012-3-1/_import.txt"
+@include "npc/012-3-2/_import.txt"
+@include "npc/012-3-3/_import.txt"
+@include "npc/020-1/_import.txt"
+@include "npc/020-2-0/_import.txt"
+@include "npc/020-2-1/_import.txt"
+@include "npc/020-2-10/_import.txt"
+@include "npc/020-2-11/_import.txt"
+@include "npc/020-2-12/_import.txt"
+@include "npc/020-2-13/_import.txt"
+@include "npc/020-2-14/_import.txt"
+@include "npc/020-2-15/_import.txt"
+@include "npc/020-2-16/_import.txt"
+@include "npc/020-2-17/_import.txt"
+@include "npc/020-2-18/_import.txt"
+@include "npc/020-2-19/_import.txt"
+@include "npc/020-2-2/_import.txt"
+@include "npc/020-2-20/_import.txt"
+@include "npc/020-2-21/_import.txt"
+@include "npc/020-2-22/_import.txt"
+@include "npc/020-2-23/_import.txt"
+@include "npc/020-2-24/_import.txt"
+@include "npc/020-2-25/_import.txt"
+@include "npc/020-2-26/_import.txt"
+@include "npc/020-2-27/_import.txt"
+@include "npc/020-2-28/_import.txt"
+@include "npc/020-2-29/_import.txt"
+@include "npc/020-2-3/_import.txt"
+@include "npc/020-2-30/_import.txt"
+@include "npc/020-2-31/_import.txt"
+@include "npc/020-2-32/_import.txt"
+@include "npc/020-2-33/_import.txt"
+@include "npc/020-2-34/_import.txt"
+@include "npc/020-2-4/_import.txt"
+@include "npc/020-2-5/_import.txt"
+@include "npc/020-2-6/_import.txt"
+@include "npc/020-2-7/_import.txt"
+@include "npc/020-2-8/_import.txt"
+@include "npc/020-2-9/_import.txt"
+@include "npc/botcheck/_import.txt"
+@include "npc/fermi/_import.txt"
+@include "npc/marine-2/_import.txt"
+@include "npc/marine/_import.txt"
+@include "npc/sec_pri/_import.txt"
+@include "npc/test/_import.txt"
+@include "npc/testbg/_import.txt"
+"npc/_anchors.txt",
diff --git a/npc/botcheck/_import.txt b/npc/botcheck/_import.txt
new file mode 100644
index 00000000..5f53d234
--- /dev/null
+++ b/npc/botcheck/_import.txt
@@ -0,0 +1,2 @@
+// Map botcheck: Botcheck Area
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
diff --git a/npc/commands/bodytype.txt b/npc/commands/bodytype.txt
new file mode 100644
index 00000000..290c6fd6
--- /dev/null
+++ b/npc/commands/bodytype.txt
@@ -0,0 +1,53 @@
+// @bodytype atcommand
+// changes or returns the body type
+
+- script @bodytype 32767,{
+ end;
+
+OnCall:
+ if (.@atcmd_parameters$[0] == "") {
+ dispbottom("Your current body type is " + bodytypeToString());
+ end;
+ }
+
+ .@desired = stringToBodytype(.@atcmd_parameters$[0]);
+
+ if (.@desired == BodyType) {
+ dispbottom("Your body type is already " + bodytypeToString());
+ } else {
+ BodyType = .@desired;
+ dispbottom("Body type changed to " + bodytypeToString());
+ }
+ end;
+
+OnInit:
+ bindatcmd("gender", "@bodytype::OnCall", 99, 99, false);
+ bindatcmd("bodytype", "@bodytype::OnCall", 99, 99, false);
+ bindatcmd("body", "@bodytype::OnCall", 99, 99, false);
+ bindatcmd("type", "@bodytype::OnCall", 99, 99, false);
+ bindatcmd("changesex", "@bodytype::OnCall", 99, 99, false);
+
+ add_group_command("gender", 40, true, false);
+ add_group_command("bodytype", 40, true, false);
+ add_group_command("body", 40, true, false);
+ add_group_command("type", 40, true, false);
+ add_group_command("changesex", 40, true, false);
+
+ add_group_command("gender", 50, true, false);
+ add_group_command("bodytype", 50, true, false);
+ add_group_command("body", 50, true, false);
+ add_group_command("type", 50, true, false);
+ add_group_command("changesex", 50, true, false);
+
+ add_group_command("gender", 60, true, false);
+ add_group_command("bodytype", 60, true, false);
+ add_group_command("body", 60, true, false);
+ add_group_command("type", 60, true, false);
+ add_group_command("changesex", 60, true, false);
+
+ add_group_command("gender", 80, true, false);
+ add_group_command("bodytype", 80, true, false);
+ add_group_command("body", 80, true, false);
+ add_group_command("type", 80, true, false);
+ add_group_command("changesex", 80, true, false);
+}
diff --git a/npc/commands/debug-look.txt b/npc/commands/debug-look.txt
new file mode 100644
index 00000000..0a4a953b
--- /dev/null
+++ b/npc/commands/debug-look.txt
@@ -0,0 +1,83 @@
+function script BarberDebug {
+ function setStyle {
+ clear;
+ setnpcdialogtitle l("Appearance Debug - Barber");
+ mes l("Hair style") + ": " + getlook(LOOK_HAIR);
+ next;
+ mes l("Please enter the desired style") + " (1-255)";
+ input .@h, 1, 0xFF;
+ setlook LOOK_HAIR, max(1, min(0xFF, .@h));
+ return;
+ }
+ function setColor {
+ clear;
+ setnpcdialogtitle l("Appearance Debug - Barber");
+ mes l("Hair color") + ": " + getlook(LOOK_HAIR_COLOR);
+ next;
+ mes l("Please enter the desired color") + " (0-255)";
+ input .@h, 0, 0xFF;
+ setlook LOOK_HAIR_COLOR, max(0, min(0xFF, .@h));
+ return;
+ }
+ function setRace {
+ clear;
+ setnpcdialogtitle l("Appearance Debug - Race");
+ mes l("Race") + ": " + Class + " (" + get_race(GETRACE_FULL) + ")";
+ next;
+ mes l("Please enter the desired race") + " (0-32767)";
+ input .@r, 0, 0x7FFF;
+ jobchange max(0, min(0x7FFF, .@r));
+ return;
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Appearance Debug");
+ mes l("This menu allows you to customize your appearance.");
+ mes "";
+
+ mes "---";
+ mes l("Body type") + ": " + bodytypeToString(BodyType);
+ mes l("Hair style") + ": " + getlook(LOOK_HAIR);
+ mes l("Hair color") + ": " + getlook(LOOK_HAIR_COLOR);
+ mes l("Race") + ": " + Class + " (" + get_race() + ")";;
+ mes "---";
+
+ next;
+ mes l("What do you want to change?");
+ select
+ menuimage("actions/edit", l("Body type") + " [" + l("Requires logout") + "]"),
+ menuimage("actions/edit", l("Hair style")),
+ menuimage("actions/edit", l("Hair color")),
+ menuimage("actions/edit", l("Race")),
+ rif(getarg(0,0), menuimage("actions/back", l("Return to Debug menu")));
+
+ switch (@menu)
+ {
+ case 1: BarberChangeBodyType(); break;
+ case 2: setStyle; break;
+ case 3: setColor; break;
+ case 4: setRace; break;
+ case 5: return;
+ }
+ } while (1);
+}
+
+
+
+- script @look 32767,{
+ end;
+
+OnCall:
+ if (!debug && !is_dev())
+ {
+ end;
+ }
+ BarberDebug;
+ closeclientdialog;
+ end;
+
+OnInit:
+ bindatcmd "look", "@look::OnCall", 0, 99, 0;
+}
diff --git a/npc/commands/debug-preset.txt b/npc/commands/debug-preset.txt
new file mode 100644
index 00000000..1fbad520
--- /dev/null
+++ b/npc/commands/debug-preset.txt
@@ -0,0 +1,253 @@
+// Preset / routine system
+// Author:
+// gumi
+// Description:
+// allows to execute multiple commands in a single step
+// to ease testing and debugging
+//
+// usage: @pre [options] <instruction>[, <instruction>...]
+// usage: DoRoutine "[options] <instruction>[, <instruction>...]";
+//
+// example: @pre -s a22 v14
+// resets all stats, gives 22 agi, gives 14 vit
+//
+// ^ actual documentation may come one day, when I feel like it
+// *hides*
+
+function script DoRoutine {
+
+ function parsev {
+ // parsev(base, patterns{, min{, max}}) => value
+ .@value = getarg(0, 0);
+ .@raw$ = getarg(1, "");
+ .@patterns = explode(.@patterns$, .@raw$, "|");
+
+ for (.@pattern = 0; .@pattern < .@patterns; ++.@pattern)
+ {
+ .@pattern$ = .@patterns$[.@pattern];
+ .@len = getstrlen(.@pattern$);
+
+ if (charat(.@pattern$, 0) == "=" && .@len >= 2)
+ {
+ .@value = atoi(delchar(.@pattern$, 0));
+ break;
+ }
+
+ else if (charat(.@pattern$, 0) == "+" && .@len >= 2)
+ {
+ if (charat(.@pattern$, 1) == "+" && getargcount() >= 4)
+ .@value = getarg(3);
+ else
+ .@value += atoi(delchar(.@pattern$, 0));
+ }
+
+ else if (charat(.@pattern$, 0) == "-" && .@len >= 2)
+ {
+ if (charat(.@pattern$, 1) == "-" && getargcount() >= 3)
+ .@value = getarg(2);
+ else
+ .@value -= atoi(delchar(.@pattern$, 0));
+ }
+
+ else if (charat(.@pattern$, 0) == ">" && .@len >= 2)
+ {
+ if (charat(.@pattern$, 1) == "=" && .@len >= 3)
+ .@value = max(atoi(substr(.@pattern$, 2, .@len - 1)), .@value);
+ else
+ .@value = max(atoi(delchar(.@pattern$, 0)) + 1, .@value);
+ }
+
+ else if (charat(.@pattern$, 0) == "<" && .@len >= 2)
+ {
+ if (charat(.@pattern$, 1) == "=" && .@len >= 3)
+ .@value = min(atoi(substr(.@pattern$, 2, .@len - 1)), .@value);
+ else
+ .@value = min(atoi(delchar(.@pattern$, 0)) - 1, .@value);
+ }
+
+ else if (.@len >= 1)
+ {
+ .@value = atoi(.@pattern$);
+ break;
+ }
+ }
+
+ if (getargcount() >= 3)
+ .@value = max(getarg(2), .@value);
+
+ if (getargcount() >= 4)
+ .@value = min(getarg(3), .@value);
+
+ return .@value;
+ }
+
+ .@routine$ = strip(getarg(0,""));
+ .@m = explode(.@routine$[0], .@routine$, " "); // prep the base array
+
+ if (charat(.@routine$[0], 0) == "-")
+ {
+ if (compare(.@routine$[0], "t"))
+ {
+ clearitem;
+ }
+
+ if (compare(.@routine$[0], "e"))
+ {
+ nude;
+ }
+
+ if (compare(.@routine$[0], "k"))
+ {
+ resetskill;
+ }
+
+ if (compare(.@routine$[0], "s"))
+ {
+ resetstatus;
+ }
+
+ if (compare(.@routine$[0], "x"))
+ {
+ resetlvl 2;
+ }
+
+ if (compare(.@routine$[0], "q"))
+ {
+ //doevent "::OnGlobalQuestReset"; // executes in all quest npcs // FIXME: maybe have a `resetquest` buildin?
+ // FIXME: ^ need a buildin that can run *right now* instead of on script end
+ }
+
+ if (compare(.@routine$[0], "n"))
+ {
+ closeclientdialog;
+ }
+
+ .@i = 1;
+ }
+
+ for (; .@i < .@m; ++.@i)
+ {
+ .@type = ord(charat(strip(.@routine$[.@i]), 0));
+
+ if (.@type > 0)
+ {
+ .@raw$ = delchar(.@routine$[.@i], 0);
+ .@args = explode(.@args$, .@raw$, ",");
+ .@a = atoi(.@args$[0]);
+ .@b = atoi(.@args$[1]);
+ .@c = atoi(.@args$[2]);
+ .@d = atoi(.@args$[3]);
+ .@e = atoi(.@args$[4]);
+
+ switch (.@type)
+ {
+ case 97: /* a => Agi */
+ .@base = readparam(bAgi);
+ statusup2 bAgi, parsev(.@base, .@args$[0], 1, 99) - .@base;
+ break;
+ case 98: /* b => body type */
+ .@desired_bt = max(1, min(3, .@a));
+ break;
+ case 99: /* c => job */
+ jobchange max(0, min(6, .@a));
+ break;
+ case 100: /* d => Dex */
+ .@base = readparam(bDex);
+ statusup2 bDex, parsev(.@base, .@args$[0], 1, 99) - .@base;
+ break;
+ case 101: /* e => equip */
+ equip max(1, min(32767, .@a));
+ break;
+ /* (f) */
+ /* (g) */
+ /* (h) */
+ case 105: /* i => Int */
+ .@base = readparam(bInt);
+ statusup2 bInt, parsev(.@base, .@args$[0], 1, 99) - .@base;
+ break;
+ /* (j) */
+ case 107: /* k => skill */
+ .@k = max(1, min(32767, .@a));
+ skill .@k, parsev(getskilllv(.@k), .@args$[1], 0, 10), 0;
+ break;
+ case 108: /* l => luk */
+ .@base = readparam(bLuk);
+ statusup2 bLuk, parsev(.@base, .@args$[0], 1, 99) - .@base;
+ break;
+ /* (m) => mercenary (reserved) */
+ /* (n) => talk to npc (reserved) */
+ /* (o) */
+ case 112: /* p => pet */
+ makepet max(1002, min(32767, .@a));
+ break;
+ case 113: /* q => quest */
+ .@q = max(0, min(32767, .@a));
+ setq .@q, parsev(getq(.@q), .@args$[1]),
+ parsev(getq2(.@q), .@args$[2]),
+ parsev(getq3(.@q), .@args$[3]),
+ parsev(getqtime(.@q), .@args$[4]);
+ break;
+ /* (r) */
+ case 115: /* s => Str */
+ .@base = readparam(bStr);
+ statusup2 bStr, parsev(.@base, .@args$[0], 1, 99) - .@base;
+ break;
+ case 116: /* t => item */
+ .@t = max(1, min(32767, .@a));
+ .@c = countitem(.@t);
+ .@v = parsev(.@c, .@args$[1], 0, 32767);
+ if (.@c > .@v)
+ delitem .@t, .@c - .@v;
+ else if (.@c < .@v)
+ getitem .@t, .@v - .@c;
+ break;
+ /* (u) */
+ case 118: /* v => vit */
+ .@base = readparam(bVit);
+ statusup2 bVit, parsev(.@base, .@args$[0], 1, 99) - .@base;
+ break;
+ case 119: /* w => warp */
+ warp .@args$[0], .@b, .@c;
+ break;
+ case 120: /* x => base level */
+ BaseLevel = parsev(BaseLevel, .@args$[0], 1, 99);
+ BaseExp = parsev(BaseExp, .@args$[1], 0);
+ break;
+ case 121: /* y => job level */
+ JobLevel = parsev(JobLevel, .@args$[0], 1, 255);
+ JobExp = parsev(JobExp, .@args$[1], 0);
+ break;
+ case 122: /* z => zeny */
+ Zeny = parsev(Zeny, .@args$[0], 0, 0x7FFFFFFE);
+ BankVault = parsev(BankVault, .@args$[1], 0, MAX_BANK_ZENY);
+ break;
+ }
+ }
+ }
+
+ if (.@desired_bt && BodyType != .@desired_bt) {
+ sleep2(500);
+ BodyType = .@desired_bt; // this forces a logout so we must be it last
+ }
+
+ return;
+}
+
+- script @pre 32767,{
+ end;
+
+OnCall:
+ if (!debug && !is_admin())
+ {
+ end;
+ }
+ if (.@atcmd_parameters$[0] != "")
+ {
+ .@atcmd_parameters$[0] = implode(.@atcmd_parameters$[0], " ");
+ }
+ DoRoutine strip(.@atcmd_parameters$[0]);
+ end;
+
+OnInit:
+ bindatcmd "pre", "@pre::OnCall", 0, 99, 0;
+}
diff --git a/npc/commands/debug-quest.txt b/npc/commands/debug-quest.txt
new file mode 100644
index 00000000..580173d0
--- /dev/null
+++ b/npc/commands/debug-quest.txt
@@ -0,0 +1,217 @@
+function script GlobalQuestDebug {
+
+ function qDebugShip {
+ function qDebugGugli {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug") + " - " + l("Prologue") + " - Gugli";
+ mes l("This menu gives access to quest debug menus for @@ quest subquests.", "Gugli");
+ next;
+ mes l("Please select a quest:");
+
+ menuint
+ menuimage("actions/back", l("Go back")), -1,
+ l("Gugli (main quest)"), ShipQuests_Gugli,
+ "Ale", ShipQuests_Ale,
+ "Astapolos", ShipQuests_Astapolos,
+ "Gulukan", ShipQuests_Gulukan,
+ "Jalad", ShipQuests_Jalad,
+ "Q'Muller", ShipQuests_QMuller,
+ "Tibbo", ShipQuests_Tibbo;
+
+ switch (@menuret)
+ {
+ case -1: return;
+ default: callfunc "QuestDebug" + @menuret;
+ }
+ } while (1);
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug") + " - " + l("Prologue");
+ mes l("This menu gives access to quest debug menus for @@ quests.", l("Prologue"));
+ next;
+ mes l("Please select a quest:");
+
+ menuint
+ menuimage("actions/back", l("Go back")), -1,
+ "Julia", ShipQuests_Julia,
+ "Arpan", ShipQuests_Arpan,
+ "Alige", ShipQuests_Alige,
+ "Peter", ShipQuests_Peter,
+ "Nard", ShipQuests_Nard,
+ l("Knife"), ShipQuests_Knife,
+ l("Money"), ShipQuests_ArpanMoney,
+ l("Door"), ShipQuests_Door,
+ "Couwan", ShipQuests_Couwan,
+ l("Treasure Chest"), ShipQuests_TreasureChest,
+ "Gugli", ShipQuests_Gugli,
+ "Gado", ShipQuests_ChefGado;
+
+ switch (@menuret)
+ {
+ case 16: qDebugGugli; break;
+ case -1: return;
+ default: callfunc "QuestDebug" + @menuret;
+ }
+ } while (1);
+ }
+
+ function qDebugArtis {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug") + " - " + l("Artis");
+ mes l("This menu gives access to quest debug menus for @@ quests.", "Artis");
+ next;
+ mes l("Please select a quest:");
+
+ menuint
+ menuimage("actions/back", l("Go back")), -1,
+ l("Lazy Brother"), ArtisQuests_LazyBrother,
+ l("Urchin"), ArtisQuests_Urchin,
+ l("Catching a piou"), ArtisQuests_CatchPiou,
+ "Eugene (" + l("fisherman") + ")", ArtisQuests_Fishman,
+ "Q'Onan", ArtisQuests_QOnan,
+ "Enora", ArtisQuests_Enora,
+ "Fexil", ArtisQuests_Fexil,
+ "Lloyd", ArtisQuests_Lloyd,
+ l("Mona's dad"), ArtisQuests_MonaDad,
+ l("Artis legion progress"), Artis_Legion_Progress,
+ l("Legion training"), ArtisQuests_TrainingLegion,
+ "Henry", ThiefQuests_Artis;
+
+ switch (@menuret)
+ {
+ case -1: return;
+ default: callfunc "QuestDebug" + @menuret;
+ }
+ } while (1);
+ }
+
+ function qDebugHurnscald {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug") + " - Hurnscald";
+ mes l("This menu gives access to quest debug menus for @@ quests.", "Hurnscald");
+ next;
+ mes l("Please select a quest:");
+
+ menuint
+ menuimage("actions/back", l("Go back")), -1,
+ "Hinnak", HurnscaldQuests_Hinnak,
+ l("Maggot soup"), HurnscaldQuests_Soup,
+ l("Inspector"), HurnscaldQuests_Inspector,
+ l("Forest bow"), HurnscaldQuests_ForestBow,
+ l("Wooden shield"), HurnscaldQuests_WoodenShield,
+ "Kfahr", HurnscaldQuests_Kfahr,
+ "Galimatia", ArgaesQuest_Galimatia,
+ "Rossy", HurnscaldQuests_Rossy;
+
+ switch (@menuret)
+ {
+ case -1: return;
+ default: callfunc "QuestDebug" + @menuret;
+ }
+ } while (1);
+ }
+
+ function qDebugGeneral {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug") + " - " + l("Other");
+ mes l("This menu gives access to quest debug menus for @@ quests.", strtolower(l("Other")));
+ next;
+ mes l("Please select a quest:");
+
+ menuint
+ menuimage("actions/back", l("Go back")), -1,
+ "Hal", General_CptHal,
+ l("Cookies"), General_Cookies,
+ "Rumly", General_Rumly,
+ l("Narrator"), General_Narrator,
+ "Janus", General_Janus,
+ l("Cooking"), General_Cooking,
+ l("Brotherhood"), General_Brotherhood;
+
+ switch (@menuret)
+ {
+ case -1: return;
+ default: callfunc "QuestDebug" + @menuret;
+ }
+ } while (1);
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes l("This menu gives access to all quest debug menus.");
+ next;
+ mes l("Please select a category:");
+
+ select
+ l("Prologue"),
+ "Artis",
+ "Hurnscald",
+ l("Other"),
+ rif(getarg(0,0), menuimage("actions/back", l("Return to Debug menu")));
+
+ switch (@menu)
+ {
+ case 1: qDebugShip; break;
+ case 2: qDebugArtis; break;
+ case 3: qDebugHurnscald; break;
+ case 4: qDebugGeneral; break;
+ case 5: return;
+ }
+ } while (1);
+}
+
+
+
+- script @qdebug 32767,{
+ end;
+
+OnCall:
+ if (!debug && !is_trusted())
+ {
+ end;
+ }
+ GlobalQuestDebug;
+ closeclientdialog;
+ end;
+
+OnSetq:
+ if (.@atcmd_numparameters < 2) {
+ dispbottom "setq called with invalid arguments (min. 2)";
+ dispbottom "GM Command syntax: @setq <quest_id> <val1> <val2> <val3>";
+ end;
+ }
+ .@q=atoi(.@atcmd_parameters$[0]);
+ switch (.@atcmd_numparameters) {
+ case 4:
+ setq3 .@q, atoi(.@atcmd_parameters$[3]);
+ case 3:
+ setq2 .@q, atoi(.@atcmd_parameters$[2]);
+ case 2:
+ setq1 .@q, atoi(.@atcmd_parameters$[1]);
+ dispbottom l("Quest %s modified by GM", getquestlink(.@q));
+ specialeffect 54, SELF, playerattached();
+ break;
+ default:
+ dispbottom "setq called with invalid arguments (max. 4)";
+ dispbottom "GM Command syntax: @setq <quest_id> <val1> <val2> <val3>";
+ break;
+ }
+ end;
+
+OnInit:
+ bindatcmd "qdebug", "@qdebug::OnCall", 0, 99, 0;
+ bindatcmd "setq", "@qdebug::OnSetq", 99, 99, 1;
+}
diff --git a/npc/commands/debug-skill.txt b/npc/commands/debug-skill.txt
new file mode 100644
index 00000000..2a3ef551
--- /dev/null
+++ b/npc/commands/debug-skill.txt
@@ -0,0 +1,94 @@
+function script GlobalSkillDebug {
+
+ function modifySkill {
+
+ function setSkill {
+ clear;
+ mes l("Enter desired skill level:");
+ input .@y;
+ skill getarg(0,1), max(0, min(10, .@y)), 0;
+ return;
+ }
+
+ setnpcdialogtitle l("Skill Debug - Modify Skill");
+ .@k = getarg(0,1);
+ .@v = getskilllv(.@k);
+ select
+ menuimage("actions/abort", l("Abort")),
+ rif(.@v > 0, menuimage("actions/remove", l("Remove this skill"))),
+ rif(.@v < 10, menuimage("actions/raise", l("Raise this skill"))),
+ rif(.@v > 0, menuimage("actions/lower", l("Lower this skill"))),
+ menuimage("actions/edit", l("Set the level manually")),
+ menuimage("actions/back", l("Return to skill debug menu"));
+
+ switch (@menu)
+ {
+ case 2: skill .@k, 0, 0; break;
+ case 3: skill .@k, min(10, .@v + 1), 0; break;
+ case 4: skill .@k, max(0, .@v - 1), 0; break;
+ case 5: setSkill .@k; break;
+ }
+
+ return;
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Skill Debug");
+ mes l("This menu allows you to change your skills.");
+ mes "";
+
+ mes "---";
+
+ .@size = getarraysize(getvariableofnpc(.debug_skills$, "@sdebug"));
+
+ for (.@s = 0; .@s < .@size; ++.@s) {
+ .@skill$ = getvariableofnpc(.debug_skills$[.@s], "@sdebug");
+ mesf("%s: %d", .@skill$, getskilllv(string_to_data(.@skill$)));
+ }
+
+ mes "---";
+
+ mes "";
+ mes l("Which skill do you wish to change?");
+ next;
+
+ .@select$ = implode(getvariableofnpc(.debug_skills$, "@sdebug"), ":");
+
+ if (getarg(0, 0)) {
+ .@select$ += ":" + menuimage("actions/back", l("Return to Debug menu"));
+ }
+
+ select(.@select$);
+
+ if (--@menu == .@size) {
+ return;
+ } else {
+ .@skill$ = getvariableofnpc(.debug_skills$[@menu], "@sdebug");
+ modifySkill(string_to_data(.@skill$));
+ }
+ } while (1);
+}
+
+
+
+- script @sdebug 32767,{
+ end;
+
+OnCall:
+ if (!debug && !is_admin())
+ {
+ end;
+ }
+ GlobalSkillDebug;
+ closeclientdialog;
+ end;
+
+OnInit:
+ setarray(.debug_skills$,
+ "NV_BASIC",
+ "EVOL_CRAFTING");
+
+ bindatcmd "sdebug", "@sdebug::OnCall", 0, 99, 0;
+}
diff --git a/npc/commands/debug.txt b/npc/commands/debug.txt
new file mode 100644
index 00000000..8cc1f1cd
--- /dev/null
+++ b/npc/commands/debug.txt
@@ -0,0 +1,145 @@
+function script GlobalDebugMenu {
+ function resetAll {
+ function doReset {
+ resetstatus;
+ resetskill;
+ resetlvl 1;
+ dispbottom l("Reset done!");
+ if (getarg(0,0) == 3)
+ {
+ closeclientdialog;
+ doevent "::OnGlobalQuestReset"; // executes in all quest npcs // FIXME: maybe have a `resetquest` buildin?
+ Zeny = 0;
+ BankVault = 0;
+ clearitem;
+ warp "000-0", 0, 0; // starting point
+ end; // script must end for doevent to execute
+ }
+ return;
+ }
+ clear;
+ setnpcdialogtitle l("Debug - Reset");
+ mes l("What do you want to reset?");
+ select
+ menuimage("actions/abort", l("Abort")),
+ menuimage("actions/reset", l("Reset stats, skills, level")),
+ menuimage("actions/nuke", l("Reset EVERYTHING")),
+ menuimage("actions/back", l("Return to Debug menu"));
+
+ switch (@menu)
+ {
+ case 2:
+ case 3: doReset @menu;
+ }
+
+ return;
+ }
+
+ function changeLevel {
+ clear;
+ setnpcdialogtitle l("Debug - Change level");
+ mes l("To change your base level, use this command:");
+ mes "";
+ mes " " + col("@blvl <" + l("delta") + ">", 3);
+ next;
+ mes l("Example:");
+ mes "@blvl 50";
+ mes " " + l("Raises your base level by 50");
+ mes "@blvl -50";
+ mes " " + l("Reduces your base level by 50");
+ next;
+ mes l("To change your job level, use this command:");
+ mes "";
+ mes " " + col("@jlvl <" + l("delta") + ">", 3);
+ next;
+ mes l("Example:");
+ mes "@jlvl 50";
+ mes " " + l("Raises your job level by 50");
+ mes "@jlvl -50";
+ mes " " + l("Reduces your job level by 50");
+ next;
+ return;
+ }
+ function changeStats {
+ clear;
+ setnpcdialogtitle l("Debug - Change stats");
+ mes l("To change your stats, use these commands:");
+ mes "";
+ mes " " + col("@str <" + l("delta") + ">", 3);
+ mes " " + col("@agi <" + l("delta") + ">", 3);
+ mes " " + col("@vit <" + l("delta") + ">", 3);
+ mes " " + col("@int <" + l("delta") + ">", 3);
+ mes " " + col("@dex <" + l("delta") + ">", 3);
+ mes " " + col("@luk <" + l("delta") + ">", 3);
+ next;
+ mes l("Example:");
+ mes "@int 50";
+ mes " " + l("Raises your Int by 50");
+ mes "@int -50";
+ mes " " + l("Reduces your Int by 50");
+ next;
+ mes l("If you simply wish to get 99 in all stats:");
+ mes "";
+ mes " " + col("@allstats", 3);
+ next;
+ mes l("If you wish to reset your stats:");
+ mes "";
+ mes " " + col("@streset", 3);
+ next;
+ return;
+ }
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Debug");
+ mes l("This menu allows you to modify your account data.");
+ mes "";
+ mes l("What do you want to do?");
+ select
+ menuimage("actions/manage", l("Change my level")),
+ menuimage("actions/manage", l("Change my stats")),
+ menuimage("actions/manage", l("Change my skills")),
+ menuimage("actions/manage", l("Change my appearance")),
+ menuimage("actions/add", l("Create items")),
+ menuimage("actions/add", l("Get money")),
+ menuimage("actions/edit", l("Change my quests")),
+ rif(debug, menuimage("actions/reset", l("Set Legacy Account"))),
+ menuimage("actions/reset", l("Reset")),
+ rif(getarg(0,0), menuimage("actions/home", l("Return to Super Menu")));
+
+ .@c = getarg(0,0) ? 2 : 1;
+
+ switch (@menu)
+ {
+ case 1: changeLevel; break;
+ case 2: changeStats; break;
+ case 3: GlobalSkillDebug .@c; break;
+ case 4: BarberDebug .@c; break;
+ case 5: closeclientdialog; clientcommand "createitems"; end;
+ case 6: Zeny = 0x7FFFFFFE; break;
+ case 7: GlobalQuestDebug .@c; break;
+ case 8: setfakelegacyaccount(); break;
+ case 9: resetAll; break;
+ case 10: return;
+ }
+ } while(1);
+}
+
+
+
+- script @debug 32767,{
+ end;
+
+OnCall:
+ if (!debug && !is_admin())
+ {
+ end;
+ }
+ GlobalDebugMenu;
+ closeclientdialog;
+ end;
+
+OnInit:
+ bindatcmd "debug", "@debug::OnCall", 0, 99, 0;
+ // TODO / FIXME: add a @test command that opens the help window for test-server
+}
diff --git a/npc/commands/event.txt b/npc/commands/event.txt
new file mode 100644
index 00000000..3f0d61de
--- /dev/null
+++ b/npc/commands/event.txt
@@ -0,0 +1,57 @@
+function script GlobalEventMenu {
+
+ function rateManagement {
+ clear;
+ mes l("To get the current rate:");
+ mes col(" @exprate", 7);
+ next;
+ mes l("To set the exp rate:");
+ mes col(" @exprate ##Brate##b hours", 7);
+ next;
+ mes l("To reset back to normal:");
+ mes col(" @exprate default", 7); // note to translators: any non-numerical value will reset so "default" is safe to translate
+ next;
+ return;
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Event Management");
+ mes l("This menu allows you to manage events and gives access to event-related tools.");
+ mes "";
+ mes l("What do you want to access?");
+
+ select
+ l("Rate management"),
+ rif(getarg(0,0), menuimage("actions/home", l("Return to Super Menu")));
+
+ //.@c = getarg(0,0) ? 2 : 1; // 1 = back to event menu, 2 = back to super menu
+
+ switch (@menu)
+ {
+ case 1: rateManagement; break;
+ default: return;
+ }
+
+ } while (true);
+}
+
+
+
+- script @event 32767,{
+ end;
+
+OnCall:
+ if (!is_evtc())
+ {
+ end;
+ }
+
+ GlobalEventMenu;
+ closeclientdialog;
+ end;
+
+OnInit:
+ bindatcmd "event", "@event::OnCall", 0, 99, 0;
+}
diff --git a/npc/commands/gm.txt b/npc/commands/gm.txt
new file mode 100644
index 00000000..b402cda8
--- /dev/null
+++ b/npc/commands/gm.txt
@@ -0,0 +1,41 @@
+// @showgm/@hidegm atcommand
+// TEMPORALY hides GM level (or revert it)
+//
+// group lv: 20+
+// group char lv: 99
+// log: False
+//
+// usage:
+// @showgm
+// #showgm "char" <delta>
+//
+
+- script @group 32767,{
+ end;
+
+OnHide:
+ .@gm=getgroupid();
+ if (.@gm < 20) end;
+ if (.@gm % 10 != 0) end;
+ setgroupid(.@gm+1);
+ dispbottom "hidelevel : "+l("Your GM level is now hidden.");
+ end;
+
+OnShow:
+ .@gm=getgroupid();
+ if (.@gm < 20) end;
+ if (.@gm % 10 != 1) end;
+ setgroupid(.@gm-1);
+ dispbottom "showlevel : "+l("Your GM level is now visible.");
+ end;
+
+OnInit:
+ bindatcmd "showgroup", "@group::OnShow", 20, 99, 0;
+ bindatcmd "showgm", "@group::OnShow", 20, 99, 0;
+ bindatcmd "showlevel", "@group::OnShow", 20, 99, 0;
+
+ bindatcmd "hidegroup", "@group::OnHide", 20, 99, 0;
+ bindatcmd "hidegm", "@group::OnHide", 20, 99, 0;
+ bindatcmd "hidelevel", "@group::OnHide", 20, 99, 0;
+ end;
+}
diff --git a/npc/commands/mobinfo.txt b/npc/commands/mobinfo.txt
new file mode 100644
index 00000000..691bfb68
--- /dev/null
+++ b/npc/commands/mobinfo.txt
@@ -0,0 +1,29 @@
+// The Mana World Script
+//
+// @monsterinfo <monsterAegis>
+// Sends @mobinfo with a delay (moved from atcommand.conf)
+// Requires EVOL_MONSTER_IDENTIFY
+//
+- script @monsterinfo 32767,{
+ end;
+
+OnCall:
+ // Check for skill level
+ if (!getskilllv(EVOL_MONSTER_IDENTIFY))
+ end;
+
+ // ...
+ if (@rsync_delay > gettimetick(2)) {
+ dispbottom l("Not doing that to prevent flood.");
+ end;
+ }
+
+ // Send @mobinfo and set a cooldown of 3 seconds.
+ atcommand("@mobinfo " + implode(.@atcmd_parameters$, " "));
+ @rsync_delay=gettimetick(2)+3;
+ end;
+
+OnInit:
+ bindatcmd "monsterinfo", "@monsterinfo::OnCall", 0, 60, 0;
+ end;
+}
diff --git a/npc/commands/motd.txt b/npc/commands/motd.txt
new file mode 100644
index 00000000..2f6a5e2a
--- /dev/null
+++ b/npc/commands/motd.txt
@@ -0,0 +1,194 @@
+function script displayMOTD {
+ .@size = getvariableofnpc(.size, "@motd");
+ .@dsize = getvariableofnpc(.dsize, "@motd");
+
+ // git stuff and such
+ if (debug)
+ {
+ for (.@i = 0; .@i < .@dsize; ++.@i)
+ {
+ dispbottom $@Debug_Messages$[.@i]; // FIXME: send this to the Debug tab instead
+ }
+
+ if (.@dsize > 0)
+ dispbottom "---";
+ }
+
+ // generic MOTD
+ for (.@i = 0; .@i < .@size; ++.@i)
+ {
+ dispbottom $MOTD_Messages$[.@i];
+ }
+
+ return;
+}
+
+function script MOTDConfig {
+
+ function toggleMOTD {
+ $MOTD_Disabled = !($MOTD_Disabled);
+ // FIXME: log to GM log
+ }
+
+ function addNewLine {
+ clear;
+ mes l("Please enter the new line.");
+ input .@s$;
+ .@s$ = strip(.@s$);
+ if (.@s$ != "")
+ {
+ .@size = getvariableofnpc(.size, "@motd");
+ $MOTD_Messages$[.@size] = .@s$;
+ set getvariableofnpc(.size, "@motd"), getarraysize($MOTD_Messages$);
+ // FIXME: log to GM log
+ }
+ }
+
+ function modifyLine {
+
+ function removeLine {
+ .@l = getarg(0);
+ deletearray $MOTD_Messages$[.@l], 1; // remove and shift
+ mes l("Line @@ has been removed.", .@l);
+ set getvariableofnpc(.size, "@motd"), getarraysize($MOTD_Messages$);
+ // FIXME: log to GM log
+ }
+
+ function moveUp {
+ .@l = getarg(0);
+ .@top$ = $MOTD_Messages$[.@l - 1];
+ $MOTD_Messages$[.@l - 1] = $MOTD_Messages$[.@l];
+ $MOTD_Messages$[.@l] = .@top$;
+ }
+
+ function moveDown {
+ .@l = getarg(0);
+ .@bottom$ = $MOTD_Messages$[.@l + 1];
+ $MOTD_Messages$[.@l + 1] = $MOTD_Messages$[.@l];
+ $MOTD_Messages$[.@l] = .@bottom$;
+ }
+
+ function editLine {
+ .@l = getarg(0);
+ clear;
+ mes l("Old line:");
+ mes "---";
+ mes $MOTD_Messages$[.@l];
+ mes "---";
+ mes "";
+ mes l("Enter new line:");
+ next;
+ input .@s$;
+ .@s$ = strip(.@s$);
+ if (.@s$ != "")
+ {
+ $MOTD_Messages$[.@l] = .@s$;
+ // FIXME: log to GM log
+ }
+ }
+
+ .@max = (getarg(0) - 1);
+
+ do
+ {
+ mes l("Enter line number:");
+ next;
+ input .@n;
+ if ($MOTD_Messages$[.@n] != "")
+ {
+ clear;
+ mes l("line @@: @@", .@n, $MOTD_Messages$[.@n]);
+ next;
+ select
+ menuimage("actions/back", l("Modify another line")),
+ menuimage("actions/remove", l("Remove this line")),
+ menuimage("actions/edit", l("Modify this line")),
+ rif(.@n > 0, menuimage("actions/raise", l("Move this line up"))),
+ rif(.@n < .@max, menuimage("actions/lower", l("Move this line down"))),
+ menuimage("actions/home", l("Return to main menu"));
+
+ switch (@menu)
+ {
+ case 2: removeLine .@n; return;
+ case 3: editLine .@n; return;
+ case 4: moveUp .@n; return;
+ case 5: moveDown .@n; return;
+ case 6: return;
+ }
+ }
+ } while (1);
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("MOTD Config");
+ mes l("This menu allows you to modify the generic message that is sent to players when they log in.");
+ mes "";
+
+ mes "---";
+ .@size = getvariableofnpc(.size, "@motd");
+ for (.@i = 0; .@i < .@size; ++.@i)
+ {
+ mes l("line @@: @@", .@i, $MOTD_Messages$[.@i]);
+ }
+ if (.@size == 0)
+ {
+ mes "(" + l("no active MOTD") + ")";
+ }
+ mes "---";
+ .@d = $MOTD_Disabled;
+ mes l("Enabled: @@", (.@d ? l("no") : l("yes")));
+ next;
+
+ select
+ menuimage("actions/toggle", (.@d ? l("Enable") : l("Disable"))),
+ menuimage("actions/add", l("Add a new line")),
+ rif(.@size, menuimage("actions/manage", l("Modify, move, or remove a line"))),
+ rif(.@size, menuimage("actions/test", l("Test MOTD"))),
+ rif(getarg(0,0), menuimage("actions/home", l("Return to Super Menu")));
+
+ switch (@menu)
+ {
+ case 1: toggleMOTD; break;
+ case 2: addNewLine; break;
+ case 3: modifyLine .@size; break;
+ case 4: displayMOTD; break;
+ default: return;
+ }
+ } while (1);
+}
+
+
+
+- script @motd 32767,{
+ end;
+
+OnCall:
+ if (!is_dev())
+ {
+ end;
+ }
+
+ MOTDConfig;
+ closeclientdialog;
+ end;
+
+OnInit:
+ MOTD_debug_text;
+ .size = getarraysize($MOTD_Messages$);
+ .dsize = getarraysize($@Debug_Messages$);
+ bindatcmd "motd", "@motd::OnCall", 0, 99, 0;
+}
+
+function script ReceiveMOTD {
+ if ($MOTD_Disabled < 1)
+ {
+ displayMOTD;
+ }
+ if (debug)
+ {
+ dispbottom "##7<<##B @@help://test-server|" + col(l("Click here for instructions on how to use the test server."),6) + "@@ ##7>>";
+ }
+ return;
+}
diff --git a/npc/commands/music.txt b/npc/commands/music.txt
new file mode 100644
index 00000000..b817b949
--- /dev/null
+++ b/npc/commands/music.txt
@@ -0,0 +1,75 @@
+// @music atcommand
+// changes the music for all players on the map
+//
+// group lv: 2
+// group char lv: 99
+// log: True
+//
+// usage:
+// @music <short name>
+//
+// example:
+// @music fun
+
+- script @music 32767,{
+ end;
+
+OnCall:
+ if (!is_evtc())
+ {
+ end;
+ }
+
+ // TODO: tmw-like argv splitter
+ .@map$ = getmap();
+
+ .@m$ = strtolower(.@atcmd_parameters$[0]);
+
+ // GMs might not know and want a list of musics
+ if (.@m$ == "" || .@m$ == "list") {
+ .@r$="list";
+
+ freeloop(true);
+ .@size=getarraysize($MUSIC_ARRAY$);
+ for (.@i = 0; .@i < .@size; ++.@i) {
+ .@r$+=", "+$MUSIC_ARRAY$[.@i];
+ }
+ freeloop(false);
+
+ dispbottom("Music list: "+.@r$);
+ end;
+ }
+
+ .@key = array_exists($MUSIC_ARRAY$, .@m$);
+
+ if (!.@key)
+ {
+ //.@m$ = implode(.@atcmd_parameters$[0], " ");
+ message(getcharid(CHAR_ID_ACCOUNT), sprintf("Can't broadcast: %s.ogg", .@m$));
+ } else {
+ message(getcharid(CHAR_ID_ACCOUNT), sprintf("Now broadcasting: %s", .@m$));
+ changemusic .@map$, .@m$ + ".ogg";
+ }
+ end;
+
+OnMyself:
+ .@m$ = strtolower(.@atcmd_parameters$[0]);
+ .@key = array_exists($MUSIC_ARRAY$, .@m$);
+
+ // TODO: Check if you have the music unlocked? Bitmask? Array?
+
+ if (!.@key)
+ {
+ //.@m$ = implode(.@atcmd_parameters$[0], " ");
+ message(getcharid(CHAR_ID_ACCOUNT), sprintf("Can't play: %s.ogg", .@m$));
+ } else {
+ message(getcharid(CHAR_ID_ACCOUNT), sprintf("Now playing: %s", .@m$));
+ changeplayermusic .@m$ + ".ogg";
+ }
+ end;
+
+OnInit:
+ bindatcmd "music", "@music::OnCall", 0, 99, 1;
+ bindatcmd "jukebox", "@music::OnMyself", 0, 50, 0;
+ end;
+}
diff --git a/npc/commands/python.txt b/npc/commands/python.txt
new file mode 100644
index 00000000..e2fdc5bf
--- /dev/null
+++ b/npc/commands/python.txt
@@ -0,0 +1,24 @@
+// The Mana World script
+// Author: Gumi <gumi@themanaworld.org>
+// Author: Jesusalva <jesusalva@themanaworld.org>
+//
+// Stomp stomp stomp (use with caution)
+
+- script @python 32767,{
+ end;
+
+// Soft Resync
+OnCall:
+ specialeffect(69, AREA, playerattached());
+ addtimer 380, .name$+"::OnKill";
+ end;
+
+OnKill:
+ percentheal -100, -100;
+ //dispbottom l("Oh look, it is Cupid!");
+ end;
+
+OnInit:
+ bindatcmd "python", "@python::OnCall", 20, 20, 1;
+ end;
+}
diff --git a/npc/commands/rate-management.txt b/npc/commands/rate-management.txt
new file mode 100644
index 00000000..995ef940
--- /dev/null
+++ b/npc/commands/rate-management.txt
@@ -0,0 +1,107 @@
+- script @exprate 32767,{
+ end;
+
+ function rateCleanUp {
+ stopnpctimer;
+ .hours = 0;
+ .max_hours = 0;
+ .current_rate = .original_exp_rate;
+ setbattleflag("base_exp_rate", .original_exp_rate);
+ setbattleflag("quest_exp_rate", .original_quest_rate);
+ charcommand("@reloadmobdb"); // this is on purpose (callable without RID)
+ charcommand("@reloadquestdb");
+ }
+
+ function remainingTime {
+ .@total_seconds = (3600 * .max_hours);
+ .@seconds_elapsed = (3600 * .hours) + (getnpctimer(0) / 1000);
+ .@seconds_remaining = max(1, .@total_seconds - .@seconds_elapsed);
+ return FuzzyTime(time_from_seconds(.@seconds_remaining), 2, 2);
+ }
+
+OnCall:
+ if (!is_evtc())
+ {
+ end;
+ }
+
+ .@special$ = strip(.@atcmd_parameters$[0]); // special value
+ .@new_rate = min(atoi(.@special$), 1000); // or just a regular integer
+ .@hours = min(0x7FFFFFFE, max(1, atoi(strip(.@atcmd_parameters$[1])))); // number of hours
+
+ if (.@new_rate > 0)
+ {
+ // set new exp rate
+ .hours = 0;
+ .max_hours = .@hours;
+ .current_rate = .@new_rate;
+ setbattleflag("base_exp_rate", .@new_rate);
+ setbattleflag("quest_exp_rate", .@new_rate);
+ charcommand("@reloadmobdb");
+ charcommand("@reloadquestdb");
+ initnpctimer; // start counting
+
+ dispbottom l("You successfully set the exp rate to @@%. It will reset to @@% (default value) in @@.",
+ .@new_rate, .original_exp_rate, FuzzyTime(time_from_hours(.max_hours), 2, 2));
+ dispbottom l("You can also manually stop it at any time with: @exprate default");
+ }
+
+ else if (.@new_rate == 0 && .@special$ == "")
+ {
+ // get current exp rate
+ if (.current_rate == .original_exp_rate)
+ {
+ dispbottom l("Current exp rate is set to @@% (default value).", .current_rate);
+ }
+
+ else
+ {
+ dispbottom l("Current exp rate is set to @@%, and will reset to @@% (default value) in @@.",
+ .current_rate, .original_exp_rate, remainingTime());
+
+ dispbottom l("If you meant to reset the exp rate to its default value: @exprate default");
+ }
+ }
+
+ else
+ {
+ // reset
+ rateCleanUp;
+ dispbottom l("Exp rate has been reset to @@% (default value).",
+ .original_exp_rate);
+ }
+
+ end;
+
+OnTimer3600000:
+ // runs every hour
+ if (++.hours == .max_hours)
+ {
+ rateCleanUp;
+ end;
+ }
+ initnpctimer;
+ end;
+
+OnPCLoginEvent:
+ if (.max_hours > 0)
+ {
+ dispbottom col(l("Exp rate is set to @@% for the next @@.",
+ .current_rate, remainingTime()), 6);
+ }
+ end;
+
+OnInit:
+ bindatcmd "exprate", "@exprate::OnCall", 0, 99, 1; // change exp rate
+
+ // WARNING: using @reloadscript will change the "original" value
+ .original_exp_rate = getbattleflag("base_exp_rate");
+ .original_quest_rate = getbattleflag("quest_exp_rate");
+ .current_rate = .original_exp_rate;
+
+ // XXX: maybe in the future:
+ //.original_item_rate = getbattleflag("item_rate_common");
+ //.original_job_rate = getbattleflag("base_job_rate");
+ //.original_pk_mode = getbattleflag("pk_mode");
+ //.original_death_penalty = getbattleflag("death_penalty_type");
+}
diff --git a/npc/commands/resync.txt b/npc/commands/resync.txt
new file mode 100644
index 00000000..a535a343
--- /dev/null
+++ b/npc/commands/resync.txt
@@ -0,0 +1,40 @@
+// Evol script
+// Author: Jesusalva <admin@tmw2.org>
+//
+// Introduces @resync
+//
+// It'll cast slide to your own position
+// Hopefully making client update your real position without causing server warning
+
+- script @resync 32767,{
+ end;
+
+// Soft Resync
+OnCall:
+ // Sliding a dead player have undesired side effects
+ if (ispcdead()) {
+ dispbottom l("Impossible to resync: You are dead.");
+ end;
+ }
+ // I add a small delay in case slide() trigger some invincibility timer or something
+ if (@rsync_delay > gettimetick(2)) {
+ dispbottom l("Not resync'ing to prevent flood.");
+ end;
+ }
+
+ // This is a hack
+ getmapxy(.@m$, .@x, .@y, 0);
+ slide .@x, .@y;
+ @rsync_delay=gettimetick(2)+rand(4,6);
+
+ // Uncomment this line to cause server to resend every packet to ManaPlus
+ // and get rid of latency effect (like dead mobs still being shown)
+ //atcommand("@refresh");
+ end;
+
+// Anyone can call @resync, but only support and upwards for other players.
+// ie. GMs can try to fix lag for other people.
+OnInit:
+ bindatcmd "resync", "@resync::OnCall", 0, 20, 0;
+ end;
+}
diff --git a/npc/commands/scheduled-broadcasts.txt b/npc/commands/scheduled-broadcasts.txt
new file mode 100644
index 00000000..8699c581
--- /dev/null
+++ b/npc/commands/scheduled-broadcasts.txt
@@ -0,0 +1,227 @@
+function script StoneBoard {
+
+ function setMessage {
+ do
+ {
+ clear;
+ mes l("Please enter the message:");
+ next;
+ input .@msg$;
+ .@msg$ = strip(.@msg$);
+ if (.@msg$ != "")
+ {
+ return .@msg$;
+ }
+ mes l("The message cannot be empty");
+ next;
+ } while (1);
+ }
+
+ function setInterval {
+ clear;
+ mes l("Please select the interval:");
+ next;
+ menuint
+ l("Every 1 hour"), 1,
+ l("Every 3 hours"), 3,
+ l("Every 5 hours"), 5,
+ l("Every 6 hours"), 6,
+ l("Every 12 hours"), 12,
+ l("Every 24 hours"), 24,
+ l("Never (only on login)"), 0;
+
+ return @menuret;
+ }
+
+ function setMaxRep {
+ if (getarg(0,0) == 0)
+ {
+ return 0;
+ }
+ clear;
+ mes l("Repeat how many times?");
+ next;
+ menuint
+ l("Send only once"), 1,
+ l("Send 2 times"), 2,
+ l("Send 3 times"), 3,
+ l("Send 5 times"), 5,
+ l("Send 10 times"), 10,
+ l("Send 20 times"), 20,
+ l("Send indefinitely"), 0;
+
+ return @menuret;
+ }
+
+ function setOnLogin {
+ if (getarg(0,0) == 0)
+ {
+ return 1;
+ }
+ clear;
+ mes l("Send this message also on login?");
+ next;
+ select
+ l("No"),
+ l("Yes");
+
+ return (@menu - 1);
+ }
+
+ function newBroadcast {
+ do
+ {
+ setnpcdialogtitle l("Scheduled broadcasts - Create new");
+
+ // go through all steps
+ .@msg$ = setMessage();
+ .@int = setInterval();
+ .@max = setMaxRep(.@int);
+ .@login = setOnLogin(.@int);
+
+ // recap
+ clear;
+ mes l("Message:");
+ mes "---";
+ mes .@msg$;
+ mes "---";
+ if (.@int)
+ {
+ mes l("Interval: every @@ hour(s)", .@int);
+ mes l("Repeat: @@ times", .@max ? .@max : "∞");
+ mes l("Sent on login: @@", .@login ? l("yes") : l("no"));
+ }
+ else
+ {
+ mes l("Interval: (none, only sent on login)");
+ mes l("Sent on login: yes");
+ }
+
+ next;
+ select
+ menuimage("actions/cancel", l("Discard")),
+ menuimage("actions/edit", l("Start over")),
+ menuimage("actions/test", l("Start broadcasting")),
+ menuimage("actions/test", l("Start broadcasting, and make an extra broadcast right now"));
+
+ switch (@menu)
+ {
+ case 3:
+ case 4:
+ stopnpctimer "@sched";
+ $@SCHED_Opt[0] = .@login;
+ $@SCHED_Opt[1] = .@int;
+ $@SCHED_Opt[2] = 0;
+ $@SCHED_Opt[3] = .@max;
+ $@SCHED_Opt[4] = 0;
+ $@SCHED_Msg$ = .@msg$;
+ if (.@int)
+ {
+ initnpctimer "@sched";
+ }
+ if (@menu == 4)
+ {
+ announce $@SCHED_Msg$, bc_all;
+ }
+ case 1: return;
+ }
+
+ } while(1);
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Scheduled broadcasts");
+ mes l("This menu allows you to set the scheduled broadcast that is sent to all players at a specific interval.");
+ mes "";
+
+ .@a = $@SCHED_Msg$ != ""; // any active broadcast?
+ mes "---";
+ mes .@a ? $@SCHED_Msg$ : "(" + l("no active broadcast") +")";
+ mes "---";
+ if (.@a)
+ {
+ mes l("Sent on login: @@", ($@SCHED_Opt[0] ? l("yes") : l("no")));
+ if ($@SCHED_Opt[1])
+ {
+ .@next = max(1, ((3600000 * ($@SCHED_Opt[1] - $@SCHED_Opt[4])) - getnpctimer(0, "@sched")));
+ mes l("Interval: every @@ hour(s)", $@SCHED_Opt[1]);
+ mes l("Next broadcast: @@", FuzzyTime(time_from_ms(.@next), 0, 99));
+ }
+ else
+ {
+ mes l("Interval: (none, only sent on login)");
+ mes l("Next broadcast: (never)");
+ }
+ mes l("Sent: @@ times out of @@", $@SCHED_Opt[2], ($@SCHED_Opt[3] ? $@SCHED_Opt[3] : "∞"));
+ }
+ next;
+
+ select
+ menuimage("actions/abort", l("Abort")),
+ rif(.@a, menuimage("actions/test", l("Manually trigger the current broadcast"))),
+ rif(.@a, menuimage("actions/remove", l("Stop broadcasting"))),
+ rif(!(.@a), menuimage("actions/add", l("Set a new broadcast"))),
+ rif(getarg(0,0), menuimage("actions/home", l("Return to Super Menu")));
+
+ switch (@menu)
+ {
+ case 2: announce $@SCHED_Msg$, bc_all; break;
+ case 3: $@SCHED_Msg$ = ""; break;
+ case 4: newBroadcast; break;
+ default: return;
+ }
+ } while (1);
+}
+
+
+
+- script @sched 32767,{
+ end;
+
+OnTimer3600000:
+ if ($@SCHED_Msg$ == "")
+ {
+ stopnpctimer;
+ end;
+ }
+
+ ++$@SCHED_Opt[4]; // increase hours counter
+ if ($@SCHED_Opt[4] == $@SCHED_Opt[1])
+ {
+ stopnpctimer;
+ ++$@SCHED_Opt[2]; // increase total counter
+ announce $@SCHED_Msg$, bc_all;
+ $@SCHED_Opt[4] = 0; // reset hours counter
+ if ($@SCHED_Opt[2] >= $@SCHED_Opt[3] && $@SCHED_Opt[3] > 0)
+ {
+ $@SCHED_Msg$ = ""; // reset message
+ end;
+ }
+ }
+ initnpctimer;
+ end;
+
+OnCall:
+ if (!is_evtc() && !is_dev())
+ {
+ end;
+ }
+
+ StoneBoard;
+ closeclientdialog;
+ end;
+
+OnInit:
+ bindatcmd "sched", "@sched::OnCall", 0, 99, 0;
+}
+
+function script ReceiveScheduledBroadcast {
+ if ($@SCHED_Opt[0] && $@SCHED_Msg$ != "")
+ {
+ announce $@SCHED_Msg$, bc_self;
+ }
+ return;
+}
+
diff --git a/npc/commands/super-menu.txt b/npc/commands/super-menu.txt
new file mode 100644
index 00000000..5ed7ced3
--- /dev/null
+++ b/npc/commands/super-menu.txt
@@ -0,0 +1,68 @@
+function script SuperMenu {
+ do
+ {
+ if (debug && !is_dev())
+ {
+ GlobalDebugMenu;
+ return;
+ }
+
+ clear;
+ setnpcdialogtitle l("Super Menu");
+ mes l("This menu contains all options available to you, based on your access privileges.");
+ mes "";
+ mes l("What do you want to access?");
+ next;
+ select
+ l("Scheduled broadcasts"),
+ l("MOTD"),
+ rif(is_evtc(), l("Event management")),
+ l("Debug");
+
+ switch (@menu)
+ {
+ case 1: StoneBoard 1; break;
+ case 2: MOTDConfig 1; break;
+ case 3: GlobalEventMenu 1; break;
+ case 4: GlobalDebugMenu 1; break;
+ }
+ } while (1);
+}
+
+
+
+- script @super 32767,{
+ end;
+
+OnCall:
+
+ if (!debug && !is_dev())
+ {
+ dispbottom l("You do not have the required access privileges to use the Super Menu.");
+ end;
+ }
+
+ SuperMenu;
+ closeclientdialog;
+ end;
+
+OnInit:
+ bindatcmd "super", "@super::OnCall", 0, 99, 0;
+ bindatcmd "numa", "@super::OnCall", 0, 99, 0; // alias for those used to TMW's @numa
+}
+
+function script GrantSuperSkill {
+ .@debug_skill = getskilllv(EVOL_SUPER_MENU);
+
+ if (.@debug_skill > 0 && !debug)
+ {
+ skill EVOL_SUPER_MENU, 0, 0; // remove debug skill. Not needed (skill tree)
+ }
+
+ else if (.@debug_skill < 1 && debug)
+ {
+ skill EVOL_SUPER_MENU, 1, 0; // give debug skill
+ }
+ return;
+}
+
diff --git a/npc/commands/warp.txt b/npc/commands/warp.txt
new file mode 100644
index 00000000..22eeda39
--- /dev/null
+++ b/npc/commands/warp.txt
@@ -0,0 +1,91 @@
+// @w atcommand
+// warps using anchors or map name
+//
+// group lv: 1
+// group char lv: 2
+// log: True
+//
+// usage:
+// @w <map or anchor> [, x [, y]]
+// #w "char" <map or anchor> [, x [, y]]
+//
+// example:
+// @w artis
+// #w "char" artis
+
+- script @w 32767,{
+ end;
+
+OnCall:
+ .@params$ = strtoupper(strip(implode(.@atcmd_parameters$[0], " ")));
+ .@request$ = replacestr(.@params$, " ", "");
+
+ cleararray($@regexmatch$[1], "", 3);
+ if (.@params$ ~= "^(.+) ([0-9]+) ([0-9]+)$")
+ {
+ .@request$ = replacestr(strip($@regexmatch$[1]), " ", "");
+ .@req_x = atoi(strip($@regexmatch$[2]));
+ .@req_y = atoi(strip($@regexmatch$[3]));
+ }
+
+ .@ht = getvariableofnpc(.ht, "__anchors__");
+ .@it = htiterator(.@ht);
+ for (.@key$ = htifirstkey(.@it); hticheck(.@it); .@key$ = htinextkey(.@it))
+ {
+ if (.@request$ ~= .@key$)
+ {
+ sscanf(htget(.@ht, .@key$, ""), "%s %d %d", .@map$, .@x, .@y);
+ break;
+ }
+ }
+ htidelete(.@it);
+
+ .@map$ = .@map$ ? .@map$ : .@request$;
+ .@x = .@req_y ? .@req_x : .@x;
+ .@y = .@req_y ? .@req_y : .@y;
+
+ if (!map_exists(.@map$))
+ {
+ if (map_exists(.@atcmd_parameters$[0]))
+ {
+ .@map$ = .@atcmd_parameters$[0];
+ }
+ else
+ {
+ dispbottom(l("Map or anchor not found: %s", .@atcmd_parameters$[0]));
+ end;
+ }
+ }
+
+ while (!checkcell(.@map$, .@x, .@y, cell_chkpass))
+ {
+ // FIXME: this whole cell finding loop is DIRTY!
+ // we should have a command to get a random free coordinate
+ // or we should make buildin_warp silently ignore 0,0
+
+ if (.@e == 50) break; // FIXME: triggers a console warning
+ .@x = rand(20, 20 + (.@e * 5));
+ .@y = rand(20, 20 + (.@e * 5));
+ ++.@e;
+ }
+
+ slide_or_warp(.@map$, .@x, .@y);
+ updateSpotlight();
+ end;
+
+OnInit:
+ if (debug > 0)
+ {
+ bindatcmd("w", "@w::OnCall", 0, 20, 0);
+ bindatcmd("go", "@w::OnCall", 0, 20, 0);
+ bindatcmd("to", "@w::OnCall", 0, 20, 0);
+ bindatcmd("warp", "@w::OnCall", 0, 20, 0);
+ }
+ else
+ {
+ bindatcmd("w", "@w::OnCall", 20, 60, 1);
+ bindatcmd("go", "@w::OnCall", 20, 60, 1);
+ bindatcmd("to", "@w::OnCall", 20, 60, 1);
+ bindatcmd("warp", "@w::OnCall", 20, 60, 1);
+ }
+}
diff --git a/npc/commands/zeny.txt b/npc/commands/zeny.txt
new file mode 100644
index 00000000..944c1bb9
--- /dev/null
+++ b/npc/commands/zeny.txt
@@ -0,0 +1,98 @@
+// @esp atcommand
+// changes the number of Esperin
+//
+// group lv: 3
+// group char lv: 99
+// log: True
+//
+// usage:
+// @esp <delta>
+// #esp "char" <delta>
+//
+// example:
+// @esp +5
+// @esp -5
+// @esp +++
+
+- script @esp 32767,{
+ end;
+
+OnCall:
+ .@delta$ = .@atcmd_parameters$[0];
+
+ if (debug && startswith(.@delta$, "--"))
+ {
+ Zeny = 0;
+ if (.@delta$ == "---")
+ {
+ BankVault = 0;
+ }
+ }
+ else if (debug && (startswith(.@delta$, "++") || .@delta$ == ""))
+ {
+ Zeny = MAX_ZENY;
+ if (.@delta$ == "+++")
+ {
+ BankVault = MAX_BANK_ZENY;
+ }
+ }
+ else
+ {
+ .@d = atoi(.@delta$);
+ if (.@d < 0)
+ {
+ .@a = Zeny + .@d; // The amount of zeny remaining after
+ if (.@a < 0) // If we can't remove that much zeny, try removing from bank too
+ {
+ Zeny = 0;
+ .@b = BankVault + .@a; // amount remaining in bank after
+ if (.@b < 0)
+ {
+ BankVault = 0;
+ }
+ else
+ {
+ BankVault += .@a;
+ }
+ }
+ else // We can remove that much zeny
+ {
+ Zeny += .@d;
+ }
+ }
+ else
+ {
+ .@a = Zeny + .@d; // The amount of zeny after
+ if (.@a < 0 || .@a >= MAX_ZENY) // If we can't add that much zeny, try adding to bank
+ {
+ .@c = .@d - (.@a - Zeny); // the amount to put in bank
+ Zeny = MAX_ZENY;
+ .@b = BankVault + .@c; // amout in bank after
+ if (.@b < 0 || .@b == MAX_BANK_ZENY)
+ {
+ BankVault = MAX_BANK_ZENY;
+ }
+ else
+ {
+ BankVault += .@c;
+ }
+ }
+ else // We can add that much zeny
+ {
+ Zeny += .@d;
+ }
+ }
+ }
+ end;
+
+OnInit:
+ if (debug > 0)
+ {
+ bindatcmd "e", "@esp::OnCall", 0, 99, 0;
+ bindatcmd "esp", "@esp::OnCall", 0, 99, 0;
+ bindatcmd "money", "@esp::OnCall", 0, 99, 0;
+ end;
+ }
+
+ bindatcmd "esp", "@esp::OnCall", 99, 99, 1;
+}
diff --git a/npc/config/hairstyle_config.txt b/npc/config/hairstyle_config.txt
new file mode 100644
index 00000000..6a43e4c8
--- /dev/null
+++ b/npc/config/hairstyle_config.txt
@@ -0,0 +1,26 @@
+// Hairstyle config
+// set array of style and colors
+
+001-2-29,37,31,0 script hairstyle_config NPC_HIDDEN,0,0,{
+
+ end;
+
+OnInit:
+ setarray $@hairstyle$[0], "(none)", "Bald", "Bowl cut", "Combed back",
+ "Emo", "Mohawk", "Pompadour", "Center parting", "Long and slick",
+ "Short and curly", "Pigtails", "Long and curly", "Parted",
+ "Perky ponytail", "Wave", "Mane", "Bun", "Wavy", "Bunches",
+ "Long ponytail", "Infinitely long", "Choppy", "Wild", "Punk",
+ "Imperial", "Side strand", "Messy", "Flat ponytail",
+ "Tapered Nape";
+
+ setarray $@haircolor$[0], "Off black", "Ash brown", "Dark brown",
+ "Dark copper", "Auburn brown", "Honey brown", "Copper blonde",
+ "Golden blonde", "Pure platinum", "Cherry blossom", "Pinky pink",
+ "Fire red", "Light violet", "Purple plum", "Navy blue",
+ "Lagoon blue", "Twisted teal", "Spring Green", "Forest Green",
+ "Silver Grey", "Esperia Blue";
+
+ setarray $@REFEXP[0], 400, 900, 2250, 6500, 15000;
+ end;
+}
diff --git a/npc/config/location.txt b/npc/config/location.txt
new file mode 100644
index 00000000..a094075f
--- /dev/null
+++ b/npc/config/location.txt
@@ -0,0 +1,83 @@
+// Moubootaur Legends Script
+// Author: Jesusalva
+// Location Config
+
+- script loc_config 32767,{
+ end;
+
+OnInit:
+ // TODO: Migglemire, Westport... As this is only used for ship right now, meh
+ setarray $@LOCMASTER_TP, TP_ARTIS, TP_TULIM, TP_HURNS, TP_CANDOR, TP_ARGAES;
+ setarray $@LOCMASTER_LOC$, "Artis", "Tulim" , "Hurns" , "Candor" , "Argaes" ;
+ setarray $@LOCMASTER_MAP$, "001-1", "020-1" , "008-1" , "012-1" , "008-1-1";
+ setarray $@LOCMASTER_X, 203, 209, 326, 63, 33;
+ setarray $@LOCMASTER_Y, 85, 143, 104, 133, 63;
+ end;
+
+OnInterIfInit:
+ // Create ship instances
+ /* La Marine's Ship */
+ // Tulim Instance
+ .TULIM_INSTID = instance_create("marine@TulimInst", 0, IOT_NONE);
+ instance_attachmap("marine", .TULIM_INSTID, 0, "marine@Tulim");
+ instance_set_timeout(0, 0, .TULIM_INSTID);
+ instance_init(.TULIM_INSTID);
+
+ // Hurns Instance
+ .HURNS_INSTID = instance_create("marine@HurnsInst", 0, IOT_NONE);
+ instance_attachmap("marine", .HURNS_INSTID, 0, "marine@Hurns");
+ instance_set_timeout(0, 0, .HURNS_INSTID);
+ instance_init(.HURNS_INSTID);
+
+ // Candor Instance
+ .CANDOR_INSTID = instance_create("marine@CandorInst", 0, IOT_NONE);
+ instance_attachmap("marine", .CANDOR_INSTID, 0, "marine@Candor");
+ instance_set_timeout(0, 0, .CANDOR_INSTID);
+ instance_init(.CANDOR_INSTID);
+
+ // Artis Instance (Frigate Gema IV)
+ .ARTIS_INSTID = instance_create("marine@ArtisInst", 0, IOT_NONE);
+ instance_attachmap("marine", .ARTIS_INSTID, 0, "marine@Artis");
+ instance_set_timeout(0, 0, .ARTIS_INSTID);
+ instance_init(.ARTIS_INSTID);
+
+ /* Other instances */
+ .GALI_INSTID = instance_create("008-1-1@galimatia", 0, IOT_NONE);
+ instance_attachmap("008-1-1", .GALI_INSTID, 0, "gali@matia");
+ instance_set_timeout(0, 0, .GALI_INSTID);
+ instance_init(.GALI_INSTID);
+ end;
+}
+
+// Warps you to last visited town
+function script ReturnLastTown {
+ PC_DEST$ = "";
+ @timer_navio_running = 0;
+ .@i=array_find($@LOCMASTER_LOC$, LOCATION$);
+ warp $@LOCMASTER_MAP$[.@i], $@LOCMASTER_X[.@i], $@LOCMASTER_Y[.@i];
+ return;
+}
+
+// Upon entering a town, save it to LOCATION$
+// EnterTown( LocName{, warp=False} )
+function script EnterTown {
+ // Fill variable
+ .@v$=getarg(0);
+
+ // Validade variable
+ if (array_find($@LOCMASTER_LOC$, .@v$) < 0) {
+ consolemes(CONSOLEMES_ERROR, "Invalid location passed to EnterTown: "+.@v$);
+ if (getarg(1, false))
+ ReturnLastTown();
+ return;
+ }
+
+ // Save location
+ LOCATION$=.@v$;
+
+ // If "warp" is true
+ if (getarg(1, false))
+ ReturnLastTown();
+ return;
+}
+
diff --git a/npc/config/magic.txt b/npc/config/magic.txt
new file mode 100644
index 00000000..dbe665a6
--- /dev/null
+++ b/npc/config/magic.txt
@@ -0,0 +1,451 @@
+// The Mana World Script
+//
+// Author: Jesusalva <jesusalva@tmw2.org>
+//
+// Magic Script Core Functions
+//
+// Imported from Moubootaur Legends
+//
+// Important Variables:
+// MAGIC_EXP
+// Current mana magic experience
+// LAST_SKILL
+// Last Skill used (array)
+// MAGIC_LVL
+// Maximum tier of usable magic, capped by something
+// MAGIC_PTS
+// Amount of used Magic Skill Points (bad logic)
+// MAGIC_CLU
+// Array of (skill ID, Level) for sk_canlevelup
+
+
+// This function will add MAGIC_EXP
+// And manage last skills used memory
+// GetManaExp(SkillID, EXP Points)
+function script GetManaExp {
+ .@sk=getarg(0);
+ .@pt=getarg(1);
+ if (LAST_SKILL == .@sk) {
+ .@pt=cap_value(.@pt/3, 0, 1);
+ .@bonus=0;
+ } else {
+ // Update skill memory
+ LAST_SKILL[4]=LAST_SKILL[3];
+ LAST_SKILL[3]=LAST_SKILL[2];
+ LAST_SKILL[2]=LAST_SKILL[1];
+ LAST_SKILL[1]=LAST_SKILL[0];
+ LAST_SKILL[0]=.@sk;
+ }
+
+ // Update Magic EXP
+ MAGIC_EXP=MAGIC_EXP+.@pt;
+ return;
+}
+
+
+
+// sk_maxpoints() → Max Magic Skill Points you may use
+// Returns how many points you can use
+// Could be tweaked to read a variable instead
+function script sk_maxpoints {
+ // 2 points per magic level
+ .@val=(MAGIC_LVL)*2;
+ // 1 point every twice magic level
+ .@val+=(MAGIC_LVL/2);
+ // Excluding first 15, 1 point every 12 job levels (Up to JL 75)
+ .@val+=min(5, ((JobLevel-15)/12));
+ // 1 point per being a player
+ .@val+=1;
+ // 2 points per Rebirth
+ .@val+=(REBIRTH*2);
+ return .@val;
+}
+
+// Returns how many points you can allocate
+// Could be tweaked to NOT use MAGIC_PTS this way
+function script sk_points {
+ return sk_maxpoints()-MAGIC_PTS;
+}
+
+// Returns true if a skill can be leveled up.
+// It checks the MSP
+// sk_canlvup( {cost=1} )
+function script sk_canlvup {
+ return ((MAGIC_PTS+getarg(0,1)) <= sk_maxpoints());
+}
+
+// Level up a skill in 1 level (internal function)
+// TODO: Return the point if leveling about Max Level
+// sk_lvup( sk{, cost=0} )
+function script sk_lvup {
+ .@lvl=MAGIC_CLU[getarg(0)];
+ getexp 0, 50*(.@lvl+1);
+ skill(getarg(0), .@lvl+1, 0);
+ if (getarg(1,0)) {
+ MAGIC_PTS+=getarg(1, 0);
+ }
+ MAGIC_CLU[getarg(0)]=.@lvl+1;
+ return;
+}
+
+// Internal Magic School Learning Interface
+// mlearn( skill, MAX_LV, MSP cost, item, amount{, GP cost} )
+// returns false if cheater; DO NOT USE IN SCRIPTS
+function script mlearn {
+ .@sk=getarg(0);
+ .@ff=getarg(1);
+ .@msp=getarg(2);
+ .@it=getarg(3);
+ .@am=getarg(4);
+ .@gp=getarg(5, 0);
+ // Max level reached
+ if (getskilllv(.@sk) >= .@ff) {
+ return true;
+ }
+ // Not enough items
+ if (countitem(.@it) < .@am)
+ return false;
+ // Not enough MSP
+ if (!sk_canlvup(.@msp))
+ return false;
+ // Not enough GP
+ if (Zeny < .@gp) {
+ return false;
+ }
+
+ // Payment
+ delitem .@it, .@am;
+ Zeny-=.@gp;
+
+ // Level up
+ sk_lvup(.@sk, .@msp);
+ return true;
+}
+
+// NEW Magic School Learning Interface
+// learn_magic(Skill)
+function script learn_magic {
+ .@ski=getarg(0);
+ .@learn$=l("Learning");
+
+ // Check if skill is valid
+ .@mlv=$@MSK_MAXLV[.@ski];
+ if (.@mlv < 1) {
+ return false;//Exception("ERROR: The skill "+.@ski+" is not valid!");
+ }
+
+ // Load a few temporary variables
+ .@pre=$@MSK_PREREQ[.@ski];
+ .@it=$@MSK_ITEM[.@ski];
+ .@am=$@MSK_AMOUNT[.@ski];
+ .@msp=$@MSK_MSPCOST[.@ski];
+ .@gp=$@MSK_COST[.@ski];
+
+ // Pre-requisite check
+ if (.@pre) {
+ if (getskilllv(.@pre) < 1) {
+ mesc l("Pre-requisites not met!"), 1;
+ mesc l("The following skill is needed: %s%s (Lv. %d)",
+ "##9", getskillname(.@pre), 1), 1;
+ return false;
+ }
+ }
+
+ // Max level reached
+ if (getskilllv(.@ski) >= .@mlv) {
+ mesc l("You've reached the maximum level for this skill."), 1;
+ return true;
+ }
+
+ // Skill level check
+ if (getskilllv(.@sk)) {
+ .@msp=1;
+ .@learn$=l("Upgrading");
+ }
+
+ mesc l("%s %s will require:", .@learn$, getskillname(.@ski));
+ mes l("* %d/%d MSP (Magic Skill Points)", .@msp, sk_points());
+ mes l("* %d/%d E (Esperins)", .@gp, Zeny);
+ mes l("* %d/%d %s", .@am, countitem(.@it), getitemlink(.@it));
+ mes "";
+ mesc l("Really learn this skill?");
+ if (askyesno() == ASK_NO)
+ return false;
+
+ return mlearn(.@ski, .@mlv, .@msp, .@it, .@am, .@gp);
+}
+
+// transcheck( {item 1, amount 1}, {item 2, amount 2}... )
+// returns true upon success
+function script transcheck {
+ if (getargcount() < 2 || getargcount() % 2 != 0)
+ return false;//Exception("Faulty learning skill command invoked - error");
+
+ // Count items
+ for (.@i=0;.@i < getargcount(); .@i++) {
+ if (countitem(getarg(.@i)) < getarg(.@i+1))
+ return false;
+ .@i++;
+ }
+
+ // Delete Items
+ for (.@i=0;.@i < getargcount(); .@i++) {
+ delitem getarg(.@i), getarg(.@i+1);
+ .@i++;
+ }
+ return true;
+}
+
+// Returns a value defining your current magic control (affects success ratio, higher is better)
+// A value of '5' means perfect control, and a value of '0' means overwhelm.
+// abizit()
+function script abizit {
+ .@lv=MAGIC_LVL+1;
+ if (.@lv < 1) return 0;
+ .@base=((.@lv*2)**3);
+ return min(MAGIC_EXP/.@base, 5);
+}
+
+
+// Reimplementation of abizit()
+// Internal helper
+// mescordialog(text, color, {dialog=1})
+function script mescordialog {
+ if (getarg(2, true))
+ mesc getarg(0), getarg(1);
+ else
+ dispbottom col(getarg(0), getarg(1));
+ return;
+}
+
+// Reimplementation of abizit()
+// It will show abizit in dialog box or in a floating message
+// ShowAbizit({dialog=1})
+function script ShowAbizit {
+ .@dial=getarg(0, true);
+ if (.@dial)
+ mesn l("Current Magic Control");
+
+ .@lv=MAGIC_LVL+1;
+ .@val=MAGIC_EXP+rand(-.@lv*5, .@lv*5);
+ .@base=((.@lv*2)**3);
+ if (.@val > .@base*5)
+ mescordialog l("You are perfectly in control of your magic."), 3, .@dial;
+ else if (.@val > .@base*4)
+ mescordialog l("You are mostly in control of your magic."), 2, .@dial;
+ else if (.@val > .@base*3)
+ mescordialog l("You are somewhat in control of your magic."), 4, .@dial;
+ else if (.@val > .@base*2)
+ mescordialog l("Your magic is more powerful than you, but you can control."), 7, .@dial;
+ else if (.@val > .@base)
+ mescordialog l("You still are overwhelmed by your magic."), 6, .@dial;
+ else
+ mescordialog l("You are completly overwhelmed by your magic."), 1, .@dial;
+ return;
+}
+
+
+/////////////////////////////////////////
+// RegisterMagic(MSP, Skill, MaxLv, Item, Amount, Class, Cost, {PreReq, PostReq})
+function script RegisterMagic {
+ .@msp=getarg(0);
+ .@ski=getarg(1);
+ .@max=getarg(2);
+ .@ite=getarg(3);
+ .@amo=getarg(4);
+ .@cla=getarg(5);
+ .@cos=getarg(6);
+ .@pre=getarg(7, false);
+ .@pos=getarg(8, false);
+
+ $@MSK_MSPCOST[.@ski]=.@msp;
+ $@MSK_MAXLV[.@ski]=.@max;
+
+ $@MSK_ITEM[.@ski]=.@ite;
+ $@MSK_AMOUNT[.@ski]=.@amo;
+ $@MSK_COST[.@ski]=.@cos;
+
+ $@MSK_PREREQ[.@ski]=.@pre;
+ $@MSK_POSTREQ[.@ski]=.@pos;
+
+ //array_push($@MSK_CLASS[.@cla], .@ski); // 3D Arrays are not supported
+ array_push($@MSK_MAGIC, .@ski);
+ return;
+}
+
+- script Magic Load NPC_HIDDEN,{
+OnInit:
+ /* RegisterMagic(MSP, Skill, MaxLv, Item, Amount,
+ Class, Cost, {PreReq, PostReq}) */
+ // (B) - Brawling
+ // (A) - Active
+ // (R) - Ranged (bows only)
+ // (M) - Magic
+ // (S) - Support
+ // (T) - Terrain
+ // (G) - GP on usage
+ // (P) - Passive
+ // (X) - Area Of Effect
+
+ //////////////////////// Other: Misc
+ // Monster Identify
+ RegisterMagic(0, EVOL_MONSTER_IDENTIFY, 1, Beer, 1,
+ CLASS_OTHER, 5000);
+ // Bash (B)
+ RegisterMagic(0, SM_BASH, 1, MagicFeather, 1,
+ CLASS_OTHER, 0);
+ // Free Cast (P)
+ RegisterMagic(0, SA_FREECAST, 1, MagicFeather, 1,
+ CLASS_OTHER, 0);
+ // Full Throttle (A)
+ RegisterMagic(0, ALL_FULL_THROTTLE, 1, MagicFeather, 1,
+ CLASS_OTHER, 0);
+
+
+ //////////////////////// Master Skill Book: Skills
+ // These skills are handled by the Master Skill Book
+ // So the definition here is duplicate.
+ // Dragon Slayer (P)
+ RegisterMagic(0, SA_DRAGONOLOGY, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // HP/DEF Boosting (P)
+ RegisterMagic(0, CR_TRUST, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // HP Recovery (P)
+ RegisterMagic(0, SM_RECOVERY, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // MP Recovery (P)
+ RegisterMagic(0, MG_SRECOVERY, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Mammonite (G)
+ RegisterMagic(0, MC_MAMMONITE, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Anti-Poison (A)
+ RegisterMagic(0, TF_DETOXIFY, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Trick Dead (A)
+ RegisterMagic(0, NV_TRICKDEAD, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Sudden Attack (A)
+ RegisterMagic(0, GC_DARKILLUSION, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+
+ //////////////////////// Master Skill Book: Spells
+ // MATK Charge (A)
+ RegisterMagic(0, HW_MAGICPOWER, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Poison (?)
+ RegisterMagic(0, TF_POISON, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Backslide (A)
+ RegisterMagic(0, TF_BACKSLIDING, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+ // Discount (P)
+ RegisterMagic(0, MC_DISCOUNT, 1, MagicFeather, 1,
+ CLASS_MASTER, 0);
+
+
+ //////////////////////// War Magic: Skills
+ // Charged Shot (R)
+ RegisterMagic(1, AC_CHARGEARROW, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+ // Arrow Shower (RX)
+ RegisterMagic(1, AC_SHOWER, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+ // Ground Strike (AX)
+ RegisterMagic(1, ASC_METEORASSAULT, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+ // Sharp Shooter (R)
+ RegisterMagic(1, SN_SHARPSHOOTING, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+ // Critical Counter Attack (A)
+ RegisterMagic(1, KN_AUTOCOUNTER, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+ // Mallard's Eye (PR)
+ RegisterMagic(1, AC_VULTURE, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+
+ //////////////////////// War Magic: Spells
+ // Soul Strike (M)
+ RegisterMagic(1, MG_SOULSTRIKE, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+ // Napalm Beat (MX)
+ RegisterMagic(1, MG_NAPALMBEAT, 1, MagicFeather, 1,
+ CLASS_WAR, 0);
+
+
+ //////////////////////// Nature Magic: Skills
+ // Nature Weapon (S)
+ RegisterMagic(1, SA_SEISMICWEAPON, 1, MagicFeather, 1,
+ CLASS_NATURE, 0);
+ // Wind Walker (A)
+ RegisterMagic(1, SN_WINDWALK, 1, MagicFeather, 1,
+ CLASS_NATURE, 0);
+ //////////////////////// Nature Magic: Spells
+ // Lightning Arrow (M)
+ RegisterMagic(1, MG_LIGHTNINGBOLT, 1, MagicFeather, 1,
+ CLASS_NATURE, 0);
+ // Nature Wall (T)
+ RegisterMagic(1, MG_FIREWALL, 1, MagicFeather, 1,
+ CLASS_NATURE, 0);
+
+
+ //////////////////////// Fire Magic: Skills
+ // Fire Weapon (S)
+ RegisterMagic(1, SA_FLAMELAUNCHER, 1, MagicFeather, 1,
+ CLASS_FIRE, 0);
+ //////////////////////// Fire Magic: Spells
+ // Fire Arrow (M)
+ RegisterMagic(1, MG_FIREBOLT, 1, MagicFeather, 1,
+ CLASS_FIRE, 0);
+ // Fire Ball (MX)
+ RegisterMagic(1, MG_FIREBALL, 1, MagicFeather, 1,
+ CLASS_FIRE, 0);
+ // Fire Walk (MX)
+ RegisterMagic(2, SO_FIREWALK, 1, MagicFeather, 1,
+ CLASS_FIRE, 0);
+
+
+ //////////////////////// Water Magic: Skills
+ // Frost Weapon (S)
+ RegisterMagic(1, SA_FROSTWEAPON, 1, MagicFeather, 1,
+ CLASS_WATER, 0);
+ //////////////////////// Water Magic: Spells
+ // Frost Diver (M)
+ RegisterMagic(1, MG_FROSTDIVER, 1, MagicFeather, 1,
+ CLASS_WATER, 0);
+ // Frost Nova (MX)
+ RegisterMagic(2, WZ_FROSTNOVA, 1, MagicFeather, 1,
+ CLASS_WATER, 0);
+
+
+ //////////////////////// Harmony Magic: Skills
+ // Provoke (A)
+ RegisterMagic(1, SM_PROVOKE, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ // Mass Provoke (A)
+ RegisterMagic(1, EVOL_MASS_PROVOKE, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ // Stealing (A)
+ RegisterMagic(1, TF_STEAL, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ // Barter (P)
+ RegisterMagic(1, MC_OVERCHARGE, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ // Backpack Floating (P)
+ RegisterMagic(1, ALL_INCCARRY, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ //////////////////////// Harmony Magic: Spells
+ // Holy Light (M)
+ RegisterMagic(1, AL_HOLYLIGHT, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ // Healing (MS)
+ RegisterMagic(1, AL_HEAL, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+ // High Healing (MS)
+ RegisterMagic(2, AB_HIGHNESSHEAL, 1, MagicFeather, 1,
+ CLASS_HARMONY, 0);
+
+ end;
+}
+
diff --git a/npc/dev/ci_test.txt b/npc/dev/ci_test.txt
new file mode 100644
index 00000000..6ee12452
--- /dev/null
+++ b/npc/dev/ci_test.txt
@@ -0,0 +1,47 @@
+//================= Hercules Script =======================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2015 Hercules Dev Team
+//= Copyright (C) 2014 Haru
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Script engine self-tests, CI integration
+//================= Description ===========================================
+//= This script depends on npc/dev/test.txt, and extends it so that it can
+//= be called in a CI environment and returns an appropriate value upon
+//= termination.
+//================= Current Version =======================================
+//= 1.0
+//================= Additional Comments ===================================
+//= This script requires the script_mapquit plugin to be loaded.
+//= Usage: ./map-server --load-plugin script_mapquit --load-script npc/dev/test.txt --load-script npc/dev/ci_test.txt
+//=========================================================================
+
+- script HerculesSelfTestCI FAKE_NPC,{
+ end;
+
+OnInit:
+ .@val = callfunc("HerculesSelfTestHelper");
+ mapquit(.@val);
+ end;
+}
diff --git a/npc/dev/test.txt b/npc/dev/test.txt
new file mode 100644
index 00000000..f98651df
--- /dev/null
+++ b/npc/dev/test.txt
@@ -0,0 +1,814 @@
+//================= Hercules Script =======================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2013-2015 Hercules Dev Team
+//= Copyright (C) 2013-2015 Haru
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Script engine self-tests
+//================= Description ===========================================
+//= Script to test operators and possibly other elements of the script
+//= engine, useful for regression testing.
+//================= Current Version =======================================
+//= 2.0
+//=========================================================================
+
+function script F_TestReturnValue {
+ return getarg(0);
+}
+
+function script F_TestScopeVars {
+ .@x = 2;
+ return .@x+1;
+}
+
+function script F_TestNPCVars {
+ .xt = 2;
+ return .xt+1;
+}
+
+function script F_TestDeepNestedScope {
+ if (getarg(0) <= 0)
+ return getarg(1); // Stop recursion
+ if (getarg(1))
+ return callfunc("F_TestDeepNestedScope", getarg(0)-1, getarg(1)); // Recursion step
+ .@x = 1;
+ return callfunc("F_TestDeepNestedScope", getarg(0)-1, .@x); // First step
+}
+
+function script F_TestDeepNestedScopeNPC2 {
+ if (getarg(0) <= 0)
+ return getarg(1); // Stop recursion
+ if (getarg(1))
+ return callfunc("F_TestDeepNestedScopeNPC", getarg(0)-1, getarg(1)); // Recursion step
+ .xt = 1;
+ return callfunc("F_TestDeepNestedScopeNPC", getarg(0)-1, .xt); // First step
+}
+
+function script F_TestDeepNestedScopeNPC {
+ if (getarg(0) <= 0)
+ return getarg(1); // Stop recursion
+ if (getarg(1))
+ return callfunc("F_TestDeepNestedScopeNPC2", getarg(0)-1, getarg(1)); // Recursion step
+ .xt = 1;
+ return callfunc("F_TestDeepNestedScopeNPC2", getarg(0)-1, .xt); // First step
+}
+
+function script F_TestNestedScope {
+ .@x = 1;
+ .@y = callfunc("F_TestReturnValue", .@x);
+ return .@y;
+}
+
+function script F_TestNestedScopeNPC {
+ .xt = 1;
+ .yt = callfunc("F_TestReturnValue", .xt);
+ return .yt;
+}
+
+function script F_TestArrayRefs {
+ return getelementofarray(getarg(0), getarraysize(getarg(0)) - 1);
+}
+
+function script F_TestReturnArrayRef {
+ setarray getarg(0), 5, 6, 7, 8;
+ return getarraysize(getarg(0));
+}
+
+function script F_TestScopeArrays {
+ setarray .@x, 1, 2, 3, 4;
+ copyarray .@y, getarg(0), getarraysize(getarg(0));
+ return getarraysize(.@y);
+}
+
+function script F_TestNPCArrays {
+ setarray .xt, 1, 2, 3, 4;
+ copyarray .yt, getarg(0), getarraysize(getarg(0));
+ return getarraysize(.yt);
+}
+
+function script F_TestVarOfAnotherNPC {
+ return getvariableofnpc(.xt, getarg(0));
+}
+
+- script TestVarOfAnotherNPC FAKE_NPC,{
+ // Used to test getvariableofnpc()
+ end;
+}
+
+function script HerculesSelfTestHelper {
+ if (.once > 0)
+ return .errors;
+ .once = 1;
+ .errors = 0;
+
+ // Callsub (basic)
+ callsub(OnCheck, "Callsub", 1, 1);
+ callsub(OnCheck, "Callsub (getarg default values)", 1);
+
+
+ // Array subscript
+ setarray .@a, 3, 2, 1;
+ callsub(OnCheck, "Array subscript", .@a[2]);
+
+
+ // Increment and decrement operators ++, --
+ .@x = 1;
+ .@y = .@x++; // .@y = .@x; .@x = .@x + 1;
+ callsub(OnCheck, "Suffix increment ++", .@y);
+ callsub(OnCheck, "Suffix increment ++", .@x, 2);
+ .@x = 1;
+ .@y = .@x--; // .@y = .@x; .@x = .@x - 1;
+ callsub(OnCheck, "Suffix decrement --", .@y);
+ callsub(OnCheck, "Suffix decrement --", .@x, 0);
+ .@x = 0;
+ .@y = ++.@x; // .@x = .@x + 1; .@y = .@x;
+ callsub(OnCheck, "Prefix increment ++", .@y);
+ callsub(OnCheck, "Prefix increment ++", .@x);
+ .@x = 2;
+ .@y = --.@x; // .@x = .@x - 1; .@y = .@x;
+ callsub(OnCheck, "Prefix decrement --", .@y);
+ callsub(OnCheck, "Prefix decrement --", .@x);
+
+ // Order of [] and --/++
+ .@a[1] = 0;
+ .@a[1]++; // .@a[1] = .@a[1] + 1;
+ callsub(OnCheck, "Order of [] and ++", .@a[1]);
+ .@a[1] = 2;
+ .@a[1]--; // .@a[1] = .@a[1] - 1;
+ callsub(OnCheck, "Order of [] and --", .@a[1]);
+
+
+ // Unary operators -, !, ~
+ .@x = 1;
+ .@y = -.@x; // .@y = 0 - .@x;
+ callsub(OnCheck, "Unary operator -", .@y, -1);
+ .@x = 1;
+ .@y = !.@x; // if(.@x == 0) .@y = 1; else .@y = 0;
+ callsub(OnCheck, "Unary operator !", .@y, 0);
+ .@x = 0x00000001;
+ .@y = ~.@x; // One's complement of 0x00000001 is 0xfffffffe, which is -2
+ callsub(OnCheck, "Unary operator ~", .@y, -2);
+
+ // Associativity of unary operators -, !, ~
+ .@x = 1;
+ .@y = ~ ! .@x; // .@y = ~(!.@x);
+ callsub(OnCheck, "Associativity of unary ~ and !", .@y, -1);
+ .@x = 0;
+ .@y = - ! .@x; // .@y = -(!.@x);
+ callsub(OnCheck, "Associativity of unary - and !", .@y, -1);
+ .@x = 1;
+ .@y = ~ - .@x; // .@y = ~(-.@x);
+ callsub(OnCheck, "Associativity of unary ~ and -", .@y, 0);
+ .@x = 1;
+ .@y = - ~ .@x; // .@y = -(~.@x);
+ callsub(OnCheck, "Associativity of unary - and ~", .@y, 2);
+
+ // Order of unary -, !, ~ and prefix/suffix ++/--
+ .@x = 2;
+ .@y = - --.@x; // .@y = -(--.@x);
+ callsub(OnCheck, "Order of unary - and prefix --", .@y, -1);
+ callsub(OnCheck, "Order of unary - and prefix --", .@x);
+ .@x = 1;
+ .@y = - .@x--; // .@y = -(.@x--);
+ callsub(OnCheck, "Order of unary - and suffix --", .@y, -1);
+ callsub(OnCheck, "Order of unary - and suffix --", .@x, 0);
+ .@x = 0;
+ .@y = - ++.@x; // .@y = -(++.@x);
+ callsub(OnCheck, "Order of unary - and prefix ++", .@y, -1);
+ callsub(OnCheck, "Order of unary - and prefix ++", .@x);
+ .@x = 1;
+ .@y = - .@x++; // .@y = -(.@x++);
+ callsub(OnCheck, "Order of unary - and suffix ++", .@y, -1);
+ callsub(OnCheck, "Order of unary - and suffix ++", .@x, 2);
+ .@x = 1;
+ .@y = !--.@x; // .@y = !(--.@x);
+ callsub(OnCheck, "Order of unary ! and prefix --", .@y);
+ callsub(OnCheck, "Order of unary ! and prefix --", .@x, 0);
+ .@x = 1;
+ .@y = !.@x--; // .@y = !(.@x--);
+ callsub(OnCheck, "Order of unary ! and suffix --", .@y, 0);
+ callsub(OnCheck, "Order of unary ! and suffix --", .@x, 0);
+ .@x = 0;
+ .@y = !++.@x; // .@y = !(++.@x);
+ callsub(OnCheck, "Order of unary ! and prefix ++", .@y, 0);
+ callsub(OnCheck, "Order of unary ! and prefix ++", .@x);
+ .@x = 0;
+ .@y = !.@x++; // .@y = !(.@x++);
+ callsub(OnCheck, "Order of unary ! and suffix ++", .@y);
+ callsub(OnCheck, "Order of unary ! and suffix ++", .@x);
+ .@x = 2;
+ .@y = ~--.@x; // .@y = ~(--.@x);
+ callsub(OnCheck, "Order of unary ~ and prefix --", .@y, -2);
+ callsub(OnCheck, "Order of unary ~ and prefix --", .@x, 1);
+ .@x = 1;
+ .@y = ~.@x--; // .@y = ~(.@x--);
+ callsub(OnCheck, "Order of unary ~ and suffix --", .@y, -2);
+ callsub(OnCheck, "Order of unary ~ and suffix --", .@x, 0);
+ .@x = 0;
+ .@y = ~++.@x; // .@y = ~(++.@x);
+ callsub(OnCheck, "Order of unary ~ and prefix ++", .@y, -2);
+ callsub(OnCheck, "Order of unary ~ and prefix ++", .@x, 1);
+ .@x = 1;
+ .@y = ~.@x++; // .@y = ~(.@x++);
+ callsub(OnCheck, "Order of unary ~ and suffix ++", .@y, -2);
+ callsub(OnCheck, "Order of unary ~ and suffix ++", .@x, 2);
+
+ // Binary *, /, % operators
+ .@x = 2 * 3; // .@x = 6;
+ callsub(OnCheck, "Binary * operator", .@x, 6);
+ .@x = 7 / 2; // .@x = 3;
+ callsub(OnCheck, "Binary / operator", .@x, 3);
+ .@x = 7 % 2; // .@x = 1;
+ callsub(OnCheck, "Binary % operator", .@x, 1);
+
+ // Associativity of *, /, %
+ .@x = 8 * 3 / 2; // .@x = (8 * 3) / 2;
+ callsub(OnCheck, "Associativity of * and /", .@x, 12);
+
+ // Order of binary *%/ and unary !-~
+ .@x = 2 * ! 3; // .@x = 2 * (!3);
+ callsub(OnCheck, "Order of binary * and unary !", .@x, 0);
+ .@x = ~ 1 * 2; // .@x = (~1) * 2;
+ callsub(OnCheck, "Order of unary ~ and binary *", .@x, -4);
+
+
+ // Binary +, - operators
+ .@x = 1 + 3; // .@x = 4;
+ callsub(OnCheck, "Binary + operator", .@x, 4);
+ .@x = 1 - 3; // .@x = -2;
+ callsub(OnCheck, "Binary - operator", .@x, -2);
+
+ // Associativity of +,-
+ .@x = 0x7fffffff - 0x7ffffff0 + 1; // .@x = (0x7fffffff - 0x7ffffff0) + 1; (without overflow)
+ callsub(OnCheck, "Associativity of + and -", .@x, 16);
+
+ // Order of +, - and *, /, %
+ .@x = 1 + 3 * 2; // .@x = 1 + (3 * 2);
+ callsub(OnCheck, "Order of + and *", .@x, 7);
+
+
+ // << and >> operators
+ .@x = 1<<3; // .@x = 1*2*2*2;
+ callsub(OnCheck, "Left shift << operator", .@x, 8);
+ .@x = 12>>2; // .@x = 12/2/2;
+ callsub(OnCheck, "Right shift >> operator", .@x, 3);
+
+ // Associativity of << and >>
+ .@x = 0x40000000 >> 4 << 2; // .@x = (0x40000000 >> 4) << 2
+ callsub(OnCheck, "Associativity of >> and <<", .@x, 0x10000000);
+
+ // Order of <</>> and +/-
+ .@x = 4 << 2 + 1; // .@x = 4 << (2+1);
+ callsub(OnCheck, "Order of << and +", .@x, 32);
+
+
+ // <, <=, >, >= operators
+ .@x = (1 < 2); // true
+ .@y = (2 < 2); // false
+ callsub(OnCheck, "< operator", .@x);
+ callsub(OnCheck, "< operator", .@y, 0);
+ .@x = (1 <= 2); // true
+ .@y = (2 <= 2); // true
+ callsub(OnCheck, "<= operator", .@x);
+ callsub(OnCheck, "<= operator", .@y);
+ .@x = (2 > 1); // true
+ .@y = (2 > 2); // false
+ callsub(OnCheck, "> operator", .@x);
+ callsub(OnCheck, "> operator", .@y, 0);
+ .@x = (2 >= 1); // true
+ .@y = (2 >= 2); // true
+ callsub(OnCheck, ">= operator", .@x);
+ callsub(OnCheck, ">= operator", .@y);
+
+ // Associativity of <,<=,>,>=
+ .@x = 1 > 0 > 0; // (1 > 0) > 0 --> 1 > 0 --> true
+ callsub(OnCheck, "Associativity of > operators", .@x);
+
+ // Order of >>/<< and </<=/>/>=
+ .@x = 1 < 1 << 2; // .@x = 1 < (1<<2);
+ callsub(OnCheck, "Order of < and <<", .@x);
+
+
+ // ==, !=, ~=, ~! operators
+ .@x = (0 == 0); // true
+ .@y = (1 == 0); // false
+ callsub(OnCheck, "== operator", .@x);
+ callsub(OnCheck, "== operator", .@y, 0);
+ .@x = (1 != 0); // true
+ .@y = (1 != 1); // false
+ callsub(OnCheck, "!= operator", .@x);
+ callsub(OnCheck, "!= operator", .@y, 0);
+ .@x$ = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
+ "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+ .@y = (.@x$ ~= "^Lorem.*, ([a-z]*).*(Duis).* ([a-z.]*)$");
+ callsub(OnCheck, "~= operator", .@y, 4);
+ callsub(OnCheck, "~= operator", $@regexmatchcount, 4);
+ if( $@regexmatchcount == 4 ) {
+ callsub(OnCheck, "~= operator", $@regexmatch$[0], .@x$);
+ callsub(OnCheck, "~= operator", $@regexmatch$[1], "quis");
+ callsub(OnCheck, "~= operator", $@regexmatch$[2], "Duis");
+ callsub(OnCheck, "~= operator", $@regexmatch$[3], "laborum.");
+ }
+ .@y = (.@x$ ~! "^Not Lorem.*, ([a-z]*).*(Duis).* ([a-z.]*)$");
+ callsub(OnCheck, "~! operator", .@y);
+
+ // Associativity of ==, !=
+ .@x = (1 == 0 == 0); // (1 == 0) == 0 --> 0 == 0 --> 1
+ .@y = (1 != 0 == 0); // (1 != 0) == 0 --> 1 == 0 --> 0
+ callsub(OnCheck, "Associativity of != and == operators", .@x);
+ callsub(OnCheck, "Associativity of != and == operators", .@y, 0);
+
+ // Order of </<=/>/>= and ==/!=
+ .@x = (1 == 2 > 1); // true
+ .@y = (1 < 2 == 1); // true
+ callsub(OnCheck, "Order of <,>,==", .@x);
+ callsub(OnCheck, "Order of <,>,==", .@y);
+
+
+ .@x$ = "string "
+ "concatenation" /* test */ " succeeded";
+ callsub(OnCheckStr, "String concatenation", .@x$, "string concatenation succeeded");
+
+
+ // Bitwise & operator
+ .@x = (7&4); // 0111 & 0100 --> 0100
+ .@y = (4&1); // 0100 & 0001 --> 0000
+ callsub(OnCheck, "Bitwise & operator", .@x, 4);
+ callsub(OnCheck, "Bitwise & operator", .@y, 0);
+
+ // Order of & and ==/!=
+ .@x = (4 == 7 & 4); // (4 == 7)&4
+ .@y = (1 & 3 != 1); // 1 & (3 != 1)
+ callsub(OnCheck, "Order of ==/!= and &", .@x, 0);
+ callsub(OnCheck, "Order of ==/!= and &", .@y);
+
+
+ // Bitwise ^ operator
+ .@x = (3^1); // 0011 ^ 0001 --> 0010
+ callsub(OnCheck, "Bitwise ^ operator", .@x, 2);
+
+ // Order of ^ and &
+ .@x = (0 & 2 ^ 2); // (0 & 2) ^ 2 --> (0000 & 0010) | 0010 --> 0000 ^ 0010 --> 0010
+ .@y = (2 ^ 2 & 0); // 2 ^ (2 & 0) --> 0010 | (0010 & 0000) --> 0010 ^ 0000 --> 0010
+ callsub(OnCheck, "Order of ^ and &", .@x, 2);
+ callsub(OnCheck, "Order of ^ and &", .@y, 2);
+
+
+ // Bitwise | operator
+ .@x = (3|4); // 0011 | 0100 --> 0111
+ .@y = (4|1); // 0100 | 0001 --> 0101
+ callsub(OnCheck, "Bitwise | operator", .@x, 7);
+ callsub(OnCheck, "Bitwise | operator", .@y, 5);
+
+ // Order of ^ and |
+ .@x = (2 ^ 2 | 2); // (2 ^ 1) | 4 --> (0010 ^ 0010) | 0010 --> 0000 | 0010 --> 0010
+ .@y = (2 | 2 ^ 2); // 4 | (1 ^ 2) --> 0010 | (0010 ^ 0010) --> 0010 | 0000 --> 0010
+ callsub(OnCheck, "Order of | and ^", .@x, 2);
+ callsub(OnCheck, "Order of | and ^", .@y, 2);
+
+
+ // Logical && operator
+ .@x = (1 && 1); // true
+ .@y = (0 && 1); // false
+ callsub(OnCheck, "Logical && operator", .@x);
+ callsub(OnCheck, "Logical && operator", .@y, 0);
+
+ // Associativity of && and short-circuit
+ .@x = 0;
+ .@y = (1 && 0 && (.@x = 1)); // should short circuit as false before evaluating the assignment
+ //FIXME callsub(OnCheck, "Short-circuit of &&", .@x, 0);
+ callsub(OnCheck, "Associativity of &&", .@y, 0);
+
+ // Order of bitwise | and logical &&
+ .@x = (1 && 0 | 4); // 1 && (0|4)
+ .@y = (4 | 0 && 1); // (4|0) && 1
+ callsub(OnCheck, "Order of && and |", .@x);
+ callsub(OnCheck, "Order of && and |", .@y);
+
+
+ // Logical || operator
+ .@x = (1 || 1); // true
+ .@y = (0 || 1); // true
+ callsub(OnCheck, "Logical || operator", .@x);
+ callsub(OnCheck, "Logical || operator", .@y);
+
+ // Associativity of || and short-circuit
+ .@x = 0;
+ .@y = (1 || 0 || (.@x = 1)); // should short circuit as true before evaluating the assignment
+ //FIXME callsub(OnCheck, "Short-circuit of ||", .@x, 0);
+ callsub(OnCheck, "Associativity of ||", .@y);
+
+ // Order of logical && and ||
+ .@x = (0 && 1 || 1); // (0 && 1) || 1
+ .@y = (1 || 1 && 0); // 1 || (1 && 0)
+ callsub(OnCheck, "Order of && and ||", .@x);
+ callsub(OnCheck, "Order of && and ||", .@y);
+
+ // Ternary conditional operator ?:
+ .@x = (1 ? 2 : 3); // 2
+ .@y = (0 ? 2 : 3); // 3
+ callsub(OnCheck, "Ternary conditional operator", .@x, 2);
+ callsub(OnCheck, "Ternary conditional operator", .@y, 3);
+
+ // Associativity of ?:
+ .@x = (1 ? 2 : 0 ? 3 : 4);
+ .@y = (1 ? 1 ? 2 : 3 : 5);
+ callsub(OnCheck, "Associativity of ?:", .@x, 2);
+ callsub(OnCheck, "Associativity of ?:", .@y, 2);
+
+ // Order of logical || and ternary ?:
+ .@x = (1 ? 0 : 0 || 1); // 1 ? 0 : (0 || 1) --> false
+ callsub(OnCheck, "Order of || and ?:", .@x, 0);
+
+
+ // Assignment operators
+ .@x = 1;
+ callsub(OnCheck, "Direct assignment operator =", .@x);
+ .@x += 7; // 1 + 7
+ callsub(OnCheck, "Assignment by sum +=", .@x, 8);
+ .@x -= 1; // 8 - 1
+ callsub(OnCheck, "Assignment by difference -=", .@x, 7);
+ .@x *= 2; // 7 * 2
+ callsub(OnCheck, "Assignment by product *=", .@x, 14);
+ .@x /= 2; // 14 / 2
+ callsub(OnCheck, "Assignment by quotient /=", .@x, 7);
+ .@x %= 4; // 7 % 4
+ callsub(OnCheck, "Assignment by remainder %=", .@x, 3);
+ .@x <<= 2; // 3 << 2
+ callsub(OnCheck, "Assignment by bitwise left shift <<=", .@x, 12);
+ .@x >>= 1; // 12 >> 1
+ callsub(OnCheck, "Assignment by bitwise right shift >>=", .@x, 6);
+ .@x &= 5; // 6 & 5 (0110 & 0101 --> 0100)
+ callsub(OnCheck, "Assignment by bitwise and &=", .@x, 4);
+ .@x ^= 5; // 4 ^ 5 (0100 ^ 0101 --> 0001)
+ callsub(OnCheck, "Assignment by bitwise xor ^=", .@x, 1);
+ .@x |= 2; // 1 | 2 (0001 | 0010 --> 0011)
+ callsub(OnCheck, "Assignment by bitwise or |=", .@x, 3);
+
+ // Associativity of assignment operators
+ .@x = 0; .@y = 0;
+ .@x = .@y = 1;
+ callsub(OnCheck, "Associativity of =", .@x);
+ callsub(OnCheck, "Associativity of =", .@y);
+ .@x = 0; .@y = 1;
+ .@x = .@y += 4;
+ callsub(OnCheck, "Associativity of = and +=", .@x, 5);
+ callsub(OnCheck, "Associativity of = and +=", .@y, 5);
+ .@x = 5; .@y = 3;
+ .@z = 8;
+ .@x *= .@y += 1;
+ callsub(OnCheck, "Associativity of *= and +=", .@x, 20);
+ callsub(OnCheck, "Associativity of *= and +=", .@y, 4);
+
+ .@x = 1; .@y = 3;
+ .@x += .@y * 10;
+ callsub(OnCheck, "Order of += and *", .@x, 31);
+ .@x = 1; .@y = 3;
+ .@x = .@y != 3 ? .@y = 2 : 4;
+ callsub(OnCheck, "Order of = and ?:", .@x, 4);
+ // FIXME callsub(OnCheck, "Short-circuit of ?:", .@y, 3);
+
+ .@x = 0;
+ if (0)
+ if (1)
+ .@x = 2;
+ else
+ .@x = 3;
+ callsub(OnCheck, "Dangling else", .@x, 0);
+
+
+ // Array operations
+ .@x[0] = 1;
+ callsub(OnCheck, "Array size (single value)", getarraysize(.@x), 1);
+ .@x[0] = 0;
+ callsub(OnCheck, "Array size (single value removal)", getarraysize(.@x), 0);
+
+ .@x[0] = 1;
+ .@x[1] = 2;
+ .@x[2] = 3;
+ .@x[5] = 4;
+ .@x[8] = 5;
+ .@x[9] = 0;
+ setarray .@y[0], 1, 2, 3, 0, 0, 4, 0, 0, 5;
+ callsub(OnCheck, "Array size (assignment)", getarraysize(.@x), 9);
+ callsub(OnCheck, "Array size (setarray)", getarraysize(.@y), 9);
+ for (.@i = 0; .@i < 10; ++.@i) {
+ callsub(OnCheck, "Array subscript and setarray [" + .@i + "]", .@x[.@i], .@y[.@i]);
+ }
+
+ cleararray .@x[1], 8, 6;
+ callsub(OnCheck, "cleararray (value) [0]", .@x[0], 1);
+ for (.@i = 1; .@i < 7; ++.@i) {
+ callsub(OnCheck, "cleararray (value) [" + .@i + "]", .@x[.@i], 8);
+ }
+ callsub(OnCheck, "cleararray (value) [7]", .@x[7], 0);
+ callsub(OnCheck, "cleararray (value) [8]", .@x[8], 5);
+ callsub(OnCheck, "cleararray (value) [9]", .@x[9], 0);
+
+ cleararray .@x, 0, getarraysize(.@x);
+ cleararray .@y, 0, getarraysize(.@y);
+ callsub(OnCheck, "cleararray and getarraysize", getarraysize(.@x), 0);
+ for (.@i = 0; .@i < 10; ++.@i) {
+ callsub(OnCheck, "cleararray (zero) [" + .@i + "]", .@x[.@i], 0);
+ }
+
+ cleararray .@x, 0, getarraysize(.@x);
+ setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
+ deletearray .@x;
+ callsub(OnCheck, "deletearray (clear) and getarraysize", getarraysize(.@x), 0);
+ for (.@i = 0; .@i < 18; ++.@i) {
+ callsub(OnCheck, "deletearray (clear) [" + .@i + "]", .@x[.@i], 0);
+ }
+
+ deletearray .@x;
+ deletearray .@y;
+ setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 0, 13, 14, 15, 16;
+ setarray .@y, 0, 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
+ deletearray .@x[9], 1;
+ callsub(OnCheck, "deletearray (single) and getarraysize", getarraysize(.@x), 16);
+ for (.@i = 0; .@i < 18; ++.@i) {
+ callsub(OnCheck, "deletearray (single) [" + .@i + "]", .@x[.@i], .@y[.@i]);
+ }
+
+ deletearray .@x;
+ deletearray .@y;
+ setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
+ setarray .@y, 0, 1, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
+ deletearray .@x[2], 4;
+ callsub(OnCheck, "deletearray (multiple) and getarraysize", getarraysize(.@x), 12);
+ for (.@i = 0; .@i < 18; ++.@i) {
+ callsub(OnCheck, "deletearray (multiple) [" + .@i + "]", .@x[.@i], .@y[.@i]);
+ }
+
+ deletearray .@x;
+ deletearray .@y;
+ setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
+ setarray .@y, 0, 1;
+ deletearray .@x[2], 1000;
+ callsub(OnCheck, "deletearray (large count) and getarraysize", getarraysize(.@x), 2);
+ for (.@i = 0; .@i < 18; ++.@i) {
+ callsub(OnCheck, "deletearray (large count) [" + .@i + "]", .@x[.@i], .@y[.@i]);
+ }
+
+ deletearray .@x;
+ deletearray .@y;
+ setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
+ setarray .@y, 0, 1;
+ deletearray .@x[2];
+ callsub(OnCheck, "deletearray (truncate) and getarraysize", getarraysize(.@x), 2);
+ for (.@i = 0; .@i < 18; ++.@i) {
+ callsub(OnCheck, "deletearray (truncate) [" + .@i + "]", .@x[.@i], .@y[.@i]);
+ }
+
+ deletearray .@x;
+ .@x[1] = 2;
+ .@x[65536] = 1;
+ callsub(OnCheck, "large array index", .@x[65536], 1);
+ callsub(OnCheck, "large array index and getarraysize", getarraysize(.@x), 65537);
+ .@x[65536] = 0;
+ callsub(OnCheck, "large array index (shrink)", .@x[65536], 0);
+ callsub(OnCheck, "large array index and getarraysize (shrink)", getarraysize(.@x), 2);
+ .@x[1] = 0;
+ callsub(OnCheck, "array shrink", .@x[1], 0);
+ callsub(OnCheck, "array shrink and getarraysize", getarraysize(.@x), 0);
+
+ // min and max
+ callsub(OnCheck, "min()", min(5, -10, 8, 3, -2, 1000), -10);
+ callsub(OnCheck, "max()", max(5, -10, 8, 3, -2, 1000), 1000);
+
+
+ // Constants
+ callsub(OnCheck, "'true' constant", true, 1);
+ callsub(OnCheck, "'false' constant", false, 0);
+ callsub(OnCheck, "'Piou' mob ID", Piou, 1002);
+ callsub(OnCheck, "'NV_BASIC' skill ID", NV_BASIC, 1);
+ callsub(OnCheck, "'Acorn' item ID", Acorn, 501);
+ callsub(OnCheck, "'Bread' item ID", Bread, 502);
+
+
+ // setd/getd
+ .@x = 1; .@x$ = ".@x";
+ callsub(OnCheck, "getd", getd(".@x"), 1);
+ callsub(OnCheck, "getd arguments", getd(.@x$), 1);
+ .@y = 0; .@y$ = ".@y";
+ setd(".@y", .@x);
+ callsub(OnCheck, "setd", .@y, 1);
+ setd(.@y$, 2);
+ callsub(OnCheck, "setd arguments", .@y, 2);
+ set getd(".@x"), getd(".@y");
+ callsub(OnCheck, "set getd", .@x, .@y);
+ .@y = 1;
+ setd(".@x", getd(".@y"));
+ callsub(OnCheck, "setd getd", .@x, .@y);
+
+ // getvariableofnpc
+ .xt = 2;
+ set getvariableofnpc(.xt, "TestVarOfAnotherNPC"), 1;
+ callsub(OnCheck, "Setting NPC variables of another NPC", getvariableofnpc(.xt, "TestVarOfAnotherNPC"), 1);
+ callsub(OnCheck, "Setting NPC variables of another NPC (local variable overwrite check)", .xt, 2);
+
+ // Callsub (advanced)
+ callsub(OnCheck, "Callsub return value", callsub(OnTestReturnValue, 1));
+ .@x = 1;
+ callsub(OnCheck, "Callsub return with scope variables", callsub(OnTestScopeVars), 3);
+ callsub(OnCheck, "Callsub (parent scope vars isolation)", .@x, 1);
+ callsub(OnCheck, "Callsub (nested scopes)", callsub(OnTestNestedScope), 1);
+ callsub(OnCheck, "Callsub (deeply nested scopes)", callsub(OnTestDeepNestedScope, 30, 0), 1);
+ .@x = 1;
+ .@y = callsub(OnSetReference, .@x);
+ callsub(OnCheck, "Callsub (setting references)", .@y, 2);
+ callsub(OnCheck, "Callsub (setting references)", .@x, 2);
+ deletearray .@x;
+ setarray .@x, 1, 2, 3, 4;
+ callsub(OnCheck, "Callsub (array references)", callsub(OnTestArrayRefs, .@x), 4);
+ deletearray .@x;
+ .@y = callsub(OnTestReturnArrayRef, .@x);
+ callsub(OnCheck, "Callsub return array references (size check)", getarraysize(.@x), .@y);
+ callsub(OnCheck, "Callsub return array references", getelementofarray(.@x, 3), 8);
+ deletearray .@x;
+ deletearray .@y;
+ setarray .@x, 1, 2;
+ .@z = getarraysize(.@x);
+ setarray .@y, 5, 6, 7, 8, 9;
+ callsub(OnCheck, "Callsub (copyarray from reference with the same name)", getarraysize(.@y), callsub(OnTestScopeArrays, .@y));
+ callsub(OnCheck, "Callsub (parent array vars isolation)", getarraysize(.@x), .@z);
+ deletearray .@x;
+ deletearray .@y;
+ .xt = 2;
+ set getvariableofnpc(.xt, "TestVarOfAnotherNPC"), 1;
+ callsub(OnCheck, "Callsub (return NPC variables from another NPC)", callsub(OnTestVarOfAnotherNPC, "TestVarOfAnotherNPC"), 1);
+ callsub(OnCheck, "Callsub (return NPC variables from another NPC - local variable overwrite check)", .xt, 2);
+
+ // Callfunc
+ callsub(OnCheck, "Callfunc return value", callfunc("F_TestReturnValue", 1));
+ .@x = 1;
+ callsub(OnCheck, "Callfunc return with scope variables", callfunc("F_TestScopeVars"), 3);
+ callsub(OnCheck, "Callfunc (parent scope vars isolation)", .@x, 1);
+ callsub(OnCheck, "Callfunc (nested scopes)", callfunc("F_TestNestedScope"), 1);
+ callsub(OnCheck, "Callfunc (deeply nested scopes)", callfunc("F_TestDeepNestedScope", 30, 0), 1);
+ deletearray .@x;
+ setarray .@x, 1, 2, 3, 4;
+ callsub(OnCheck, "Callfunc (array references)", callfunc("F_TestArrayRefs", .@x), 4);
+ deletearray .@x;
+ .@y = callfunc("F_TestReturnArrayRef", .@x);
+ callsub(OnCheck, "Callfunc return array references (size check)", getarraysize(.@x), .@y);
+ callsub(OnCheck, "Callfunc return array references", getelementofarray(.@x, 3), 8);
+ deletearray .@x;
+ deletearray .@y;
+ setarray .@x, 1, 2;
+ .@z = getarraysize(.@x);
+ setarray .@y, 5, 6, 7, 8, 9;
+ callsub(OnCheck, "Callfunc (copyarray from reference with the same name)", getarraysize(.@y), callfunc("F_TestScopeArrays", .@y));
+ callsub(OnCheck, "Callfunc (parent array vars isolation)", getarraysize(.@x), .@z);
+ deletearray .@x;
+ deletearray .@y;
+ .xt = 1;
+ callsub(OnCheck, "Callfunc return with NPC variables", callfunc("F_TestNPCVars"), 3);
+ callsub(OnCheck, "Callfunc (parent NPC vars isolation)", .xt, 1);
+ callsub(OnCheck, "Callfunc (nested scopes and NPC variables)", callfunc("F_TestNestedScopeNPC"), 1);
+ callsub(OnCheck, "Callfunc (deeply nested scopes and NPC variables)", callfunc("F_TestDeepNestedScopeNPC", 30, 0), 1);
+ deletearray .xt;
+ setarray .xt, 1, 2, 3, 4;
+ callsub(OnCheck, "Callfunc (array references and NPC variables)", callfunc("F_TestArrayRefs", .xt), 4);
+ deletearray .xt;
+ .yt = callfunc("F_TestReturnArrayRef", .xt);
+ callsub(OnCheck, "Callfunc return array references with NPC variables (size check)", getarraysize(.xt), .yt);
+ callsub(OnCheck, "Callfunc return array references wuth NPC variables", getelementofarray(.xt, 3), 8);
+ deletearray .xt;
+ deletearray .yt;
+ setarray .xt, 1, 2;
+ .@z = getarraysize(.@x);
+ setarray .yt, 5, 6, 7, 8, 9;
+ callsub(OnCheck, "Callfunc (copyarray from NPC variable reference with the same name)", getarraysize(.@y), callfunc("F_TestNPCArrays", .@y));
+ callsub(OnCheck, "Callfunc (parent array NPC vars isolation)", getarraysize(.@x), .@z);
+ deletearray .xt;
+ deletearray .yt;
+ .xt = 2;
+ set getvariableofnpc(.xt, "TestVarOfAnotherNPC"), 1;
+ callsub(OnCheck, "Callfunc (return NPC variables from another NPC)", callfunc("F_TestVarOfAnotherNPC", "TestVarOfAnotherNPC"), 1);
+ callsub(OnCheck, "Callfunc (return NPC variables from another NPC - local variable overwrite check)", .xt, 2);
+
+ callsub(OnCheckStr, "sprintf (%%)", sprintf("'%%'"), "'%'");
+ callsub(OnCheckStr, "sprintf (%d)", sprintf("'%d'", 5), "'5'");
+ callsub(OnCheckStr, "sprintf (neg. %d)", sprintf("'%d'", -5), "'-5'");
+ callsub(OnCheckStr, "sprintf (%u)", sprintf("'%u'", 5), "'5'");
+ callsub(OnCheckStr, "sprintf (%x)", sprintf("'%x'", 10), "'a'");
+ callsub(OnCheckStr, "sprintf (%X)", sprintf("'%X'", 31), "'1F'");
+ callsub(OnCheckStr, "sprintf (%s)", sprintf("'%s'", "Hello World!"), "'Hello World!'");
+ callsub(OnCheckStr, "sprintf (%c)", sprintf("'%c'", "Hello World!"), "'H'");
+ callsub(OnCheckStr, "sprintf (%+d)", sprintf("'%+d'", 5), "'+5'");
+ callsub(OnCheckStr, "sprintf (%{n}d)", sprintf("'%5d'", 5), "' 5'");
+ callsub(OnCheckStr, "sprintf (%-{n}d)", sprintf("'%-5d'", 5), "'5 '");
+ callsub(OnCheckStr, "sprintf (%-+{n}d)", sprintf("'%-+5d'", 5), "'+5 '");
+ callsub(OnCheckStr, "sprintf (%+0{n}d)", sprintf("'%+05d'", 5), "'+0005'");
+ callsub(OnCheckStr, "sprintf (%0*d)", sprintf("'%0*d'", 5, 10), "'00010'");
+ callsub(OnCheckStr, "sprintf (Two args)", sprintf("'%+05d' '%x'", 5, 0x7f), "'+0005' '7f'");
+ callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$+05d'", 5, 6), "'+0006'");
+ callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$s' '%1$c'", "First", "Second"), "'Second' 'F'");
+
+ if (.errors) {
+ consolemes(CONSOLEMES_DEBUG, "Script engine self-test [ \033[0;31mFAILED\033[0m ]");
+ consolemes(CONSOLEMES_ERROR, "**** The test was completed with " + .errors + " errors. ****");
+ } else {
+ consolemes(CONSOLEMES_DEBUG, "Script engine self-test [ \033[0;32mPASSED\033[0m ]");
+ }
+ return .errors;
+ end;
+
+OnTestReturnValue:
+ return getarg(0);
+
+OnTestScopeVars:
+ .@x = 2;
+ return .@x+1;
+
+OnTestDeepNestedScope:
+ if (getarg(0) <= 0)
+ return getarg(1); // Stop recursion
+ if (getarg(1))
+ return callsub(OnTestDeepNestedScope, getarg(0)-1, getarg(1)); // Recursion step
+ .@x = 1;
+ return callsub(OnTestDeepNestedScope, getarg(0)-1, .@x); // First step
+
+OnTestNestedScope:
+ .@x = 1;
+ .@y = callsub(OnTestReturnValue, .@x);
+ return .@y;
+
+OnTestArrayRefs:
+ return getelementofarray(getarg(0), getarraysize(getarg(0)) - 1);
+
+OnTestReturnArrayRef:
+ setarray getarg(0), 5, 6, 7, 8;
+ return getarraysize(getarg(0));
+
+OnTestScopeArrays:
+ setarray .@x, 1, 2, 3, 4;
+ copyarray .@y, getarg(0), getarraysize(getarg(0));
+ return getarraysize(.@y);
+
+OnTestVarOfAnotherNPC:
+ return getvariableofnpc(.xt, getarg(0));
+
+OnReportError:
+ .@msg$ = getarg(0,"Unknown Error");
+ .@val$ = getarg(1,"");
+ .@ref$ = getarg(2,"");
+ if (.errors == 1)
+ consolemes(CONSOLEMES_ERROR, "**** WARNING: Any self-test results past this point are unreliable because of previous errors. ****");
+ consolemes(CONSOLEMES_ERROR, "Error: "+.@msg$+": '"+.@val$+"' (found) != '"+.@ref$+"' (expected)");
+ ++.errors;
+ //end;
+ return;
+
+OnCheck:
+ .@msg$ = getarg(0,"Unknown Error");
+ .@val = getarg(1,0);
+ .@ref = getarg(2,1);
+ if (.@val != .@ref) {
+ callsub(OnReportError, .@msg$, ""+.@val, ""+.@ref); // String coercion
+ }
+ return;
+OnCheckStr:
+ .@msg$ = getarg(0,"Unknown Error");
+ .@val$ = getarg(1,"");
+ .@ref$ = getarg(2,"");
+ if (.@val$ != .@ref$) {
+ callsub(OnReportError, .@msg$, .@val$, .@ref$);
+ }
+ return;
+OnSetReference:
+ set getarg(0), getarg(0) + 1;
+ return getarg(0);
+}
+
+- script HerculesSelfTest FAKE_NPC,{
+ end;
+
+OnInit:
+ callfunc("HerculesSelfTestHelper");
+ end;
+}
diff --git a/npc/fermi/_import.txt b/npc/fermi/_import.txt
new file mode 100644
index 00000000..9c2eafa4
--- /dev/null
+++ b/npc/fermi/_import.txt
@@ -0,0 +1,3 @@
+// Map fermi: Three Fermi Land
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/fermi/_warps.txt",
diff --git a/npc/fermi/_warps.txt b/npc/fermi/_warps.txt
new file mode 100644
index 00000000..9da4df68
--- /dev/null
+++ b/npc/fermi/_warps.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map fermi: Three Fermi Land warps
+fermi,29,19,0 warp #fermi_29_19 0,0,marine,43,27
diff --git a/npc/functions/RNGesus.txt b/npc/functions/RNGesus.txt
new file mode 100644
index 00000000..7224977c
--- /dev/null
+++ b/npc/functions/RNGesus.txt
@@ -0,0 +1,87 @@
+// Evol functions.
+// Authors:
+// gumi
+// jesusalva
+// Description:
+// Randomization helper functions.
+
+// pseudo-fix randomness
+// rand2( min, max )
+function script rand2 {
+ if (getargcount() == 2) {
+ .@min=getarg(0)*100;
+ .@max=getarg(1)*100+99;
+ } else {
+ .@min=0;
+ .@max=getarg(0)*100-1;
+ }
+ return rand(.@min, .@max)/100;
+}
+
+
+
+// any(<arg>{, ...<arg>})
+// returns one argument randomly
+
+function script any {
+ return getarg(rand2(getargcount()));
+}
+
+
+
+// any_of(<array>)
+// returns any member of the array
+
+function script any_of {
+ return getelementofarray(getarg(0), getarrayindex(getarg(0)) + rand2(getarraysize(getarg(0)) - getarrayindex(getarg(0))));
+}
+
+
+
+// relative_array_random(<array: 0, {[value, probability]..}>)
+// returns a random entry from the array, by relative probability
+// the first key of the array should be 0 and every entries are a tuple
+// of [value, probability]
+
+function script relative_array_random {
+ .@is_str = getdatatype(getarg(0)) & DATATYPE_STR;
+ .@total_prob = getelementofarray(getarg(0), 0);
+ .@initial_index = getarrayindex(getarg(0));
+ .@initial_index = .@initial_index ? .@initial_index : 1;
+ freeloop(true);
+
+ if (.@total_prob < 1 || getarg(1, false))
+ {
+ // first calculation, or forced re-calculation
+ .@total_prob = 0;
+ .@size = getarraysize(getarg(0));
+
+ for (.@i = .@initial_index + 1; .@i < .@size; .@i += 2) {
+ if (.@is_str) {
+ .@total_prob += max(1, atoi(getelementofarray(getarg(0), .@i)));
+ } else {
+ .@total_prob += max(1, getelementofarray(getarg(0), .@i));
+ }
+ }
+
+ // we cache on the first key
+ set(getelementofarray(getarg(0), 0), .@total_prob);
+ }
+
+ .@target_sum = rand2(0, .@total_prob);
+
+ for (.@i = .@initial_index; .@sum < .@target_sum; .@i += 2) {
+ if (.@is_str) {
+ .@sum += atoi(getelementofarray(getarg(0), .@i + 1));
+ } else {
+ .@sum += getelementofarray(getarg(0), .@i + 1);
+ }
+
+ if (.@sum >= .@target_sum) {
+ break;
+ }
+ }
+
+ freeloop(false);
+ return getelementofarray(getarg(0), .@i);
+}
diff --git a/npc/functions/afk.txt b/npc/functions/afk.txt
new file mode 100644
index 00000000..9790ea1a
--- /dev/null
+++ b/npc/functions/afk.txt
@@ -0,0 +1,69 @@
+// Moubootaur Legends Script
+// Author:
+// Jesusalva
+// Hocus Pocus Fidibus
+// Micksha
+// Description:
+// Professor - allows you to gain EXP for idling (Speech skill)
+// Modified for The Mana World. Please update the bottom of this file always.
+
+// AFKLoop(label, map, x1, y1, x2, y2)
+function script AFKLoop {
+ deltimer(getarg(0)); // safeguard
+ .@m$=getarg(1);
+ .@x1=getarg(2);
+ .@y1=getarg(3);
+ .@x2=getarg(4);
+ .@y2=getarg(5);
+
+ // Limit maximum AFK TIme using the same rule as Moubootaur Legends
+ // Max AFK time is determined as 30 minutes + 1 second every 10 minutes AFKed
+ // Capped at 2 hours (you've AFK'ed 37 days and 12 hours - 900 hours)
+ .@maxafk=min(7200, 1800+(AFKING/600));
+
+ // Check if this timer is still relevant
+ if (getmap() != .@m$)
+ return false;
+
+ addtimer2(3000, getarg(0));
+
+ // To receive AFK experience, you must be sitting at the table...
+ if (!isin(.@m$, .@x1, .@y1, .@x2, .@y2))
+ return false;
+
+ // ...And be idle for less than .@maxafk
+ if (checkidle() > .@maxafk)
+ return false;
+
+ // Calculate amount of EXP based on players in the square
+ // Every 2 players grant you 1 XP, capped at 10 xp
+ // For job experience, it is twice as difficult.
+ .@ppl=getareausers(.@m$, .@x1, .@y1, .@x2, .@y2);
+ .@bxp=cap_value(1+.@ppl/2 , 1, 10);
+ .@jxp=cap_value(1+.@ppl/4 , 1, 5);
+
+ // Beer and Red Plush Wine modifiers
+ if (getstatus(SC_CONFUSION)) {
+ .@bxp+=1;
+ //.@jxp+=1;
+ } else {
+ .@bxp=1;
+ .@jxp=1;
+ }
+
+ // Increase time AFK'ed timers and grant experience
+ AFKING+=1;
+ getexp .@bxp, .@jxp;
+ return true;
+}
+
+// Record memory for player login, re-firing timers when player is in a bar.
+function script AFKLogin {
+ .@m$=getmap();
+ if (.@m$ == "008-2-2")
+ addtimer2(3000, "#AFKHurns::OnSpeeching");
+ else if (.@m$ == "001-2-28")
+ addtimer2(3000, "#AFKArtis::OnSpeeching");
+ return;
+}
+
diff --git a/npc/functions/array.txt b/npc/functions/array.txt
new file mode 100644
index 00000000..6093aa32
--- /dev/null
+++ b/npc/functions/array.txt
@@ -0,0 +1,445 @@
+// array_pad(<array>, <size>, <value>)
+// prepend or append <value> until the array is of <size> size
+// returns the amount added on success, or false (0) if nothing changed
+
+function script array_pad {
+ .@index = getarrayindex(getarg(0)); // passed index
+ .@count = getarraysize(getarg(0)) - .@index; // actual size
+ .@size = getarg(1); // desired size
+ .@absolute = (.@size >= 0 ? .@size : -(.@size)); // |size|
+ .@delta = .@absolute - .@count; // amount to fill
+
+ if (.@absolute <= .@count) {
+ return false; // nothing to do
+ }
+
+ if (.@size < 0) {
+ copyarray(getelementofarray(getarg(0), .@index + .@delta), getarg(0), .@count); // shift to the right
+ cleararray(getarg(0), getarg(2), .@delta); // prepend
+ } else {
+ cleararray(getelementofarray(getarg(0), .@index + .@count), getarg(2), .@delta); // append
+ }
+
+ return .@delta;
+}
+
+
+
+// array_replace(<array>, <needle>, <replace>{, <neq>})
+// replace every occurence of <needle> with <replace>
+// returns the number of replaced elements
+
+function script array_replace {
+ .@size = getarraysize(getarg(0));
+ .@neq = getarg(3, false);
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) ||
+ (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) {
+ set(getelementofarray(getarg(0), .@i), getarg(2));
+ ++.@count;
+ }
+ }
+
+ freeloop(false);
+ return .@count;
+}
+
+
+
+// array_find(<array>, <needle>{, <neq>})
+// return the index of the first occurence of <needle> in <array>
+// if not found it returns -1
+
+function script array_find {
+ .@size = getarraysize(getarg(0));
+ .@neq = getarg(2, false);
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) ||
+ (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) {
+ freeloop(false);
+ return .@i;
+ }
+ }
+
+ freeloop(false);
+ return -1;
+}
+
+
+
+// array_rfind(<array>, <needle>{, <neq>})
+// return the index of the last occurence of <needle> in <array>
+// if not found it returns -1
+
+function script array_rfind {
+ .@min = getarrayindex(getarg(0));
+ .@neq = getarg(2, false);
+ freeloop(true);
+
+ for (.@i = (getarraysize(getarg(0)) - 1); .@i >= .@min; --.@i) {
+ if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) ||
+ (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) {
+ freeloop(false);
+ return .@i;
+ }
+ }
+
+ freeloop(false);
+ return -1;
+}
+
+
+
+// array_exists(<array>, <needle>{, <neq>})
+// return true or false accordingly if <needle> is found in <array>
+
+function script array_exists {
+ return array_find(getarg(0), getarg(1), getarg(2, false)) > -1;
+}
+
+
+
+// array_count(<array>, <needle>{, <neq>})
+// counts the number of occurrence of <needle> in the <array>
+
+function script array_count {
+ .@size = getarraysize(getarg(0));
+ .@neq = getarg(2, false);
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) ||
+ (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) {
+ ++.@count;
+ }
+ }
+
+ freeloop(false);
+ return .@count;
+}
+
+
+
+// array_entries(<array>)
+// returns the number of non-empty entries
+
+function script array_entries {
+ if (isstr(getarg(0)) == 1) {
+ return array_count(getarg(0), "", true);
+ }
+ return array_count(getarg(0), 0, true);
+}
+
+
+
+// array_remove(<array>, <needle>{, <neq>})
+// removes every occurrence of <needle> in the <array> while shifting left
+
+function script array_remove {
+ .@size = getarraysize(getarg(0));
+ .@neq = getarg(2, false);
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) ||
+ (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) {
+ deletearray(getelementofarray(getarg(0), .@i), 1); // shift left
+ ++.@count; // increase the counter
+ --.@size; // reduce the size
+ --.@i; // step back
+ }
+ }
+
+ freeloop(false);
+ return .@count;
+}
+
+
+
+// array_reverse(<array>)
+// reverses the array
+
+function script array_reverse {
+ .@index = getarrayindex(getarg(0));
+ .@size = getarraysize(getarg(0));
+ freeloop(true);
+
+ for (.@i = .@index; .@i < ((.@size + .@index) / 2); ++.@i) {
+ swap(getelementofarray(getarg(0), .@i), getelementofarray(getarg(0), .@size + .@index - 1 - .@i)); // a <> b
+ }
+
+ freeloop(false);
+ return true;
+}
+
+
+
+// array_sum(<array>)
+// return the sum of every element of the array
+
+function script array_sum {
+ .@size = getarraysize(getarg(0));
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ .@sum += getelementofarray(getarg(0), .@i);
+ }
+
+ freeloop(false);
+ return .@sum;
+}
+
+
+
+// array_difference(<array>)
+// return the difference of every element of the array
+
+function script array_difference {
+ .@size = getarraysize(getarg(0));
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ .@diff -= getelementofarray(getarg(0), .@i);
+ }
+
+ freeloop(false);
+ return .@diff;
+}
+
+
+
+// array_product(<array>)
+// return the product of every element of the array
+
+function script array_product {
+ .@size = getarraysize(getarg(0));
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ .@prod *= getelementofarray(getarg(0), .@i);
+ }
+
+ freeloop(false);
+ return .@prod;
+}
+
+
+
+// array_quotient(<array>)
+// return the product of every element of the array
+
+function script array_quotient {
+ .@size = getarraysize(getarg(0));
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ .@quot /= getelementofarray(getarg(0), .@i);
+ }
+
+ freeloop(false);
+ return .@quot;
+}
+
+
+
+// array_shift(<array>)
+// returns the first element of the array and removes it, while shifting left
+
+function script array_shift {
+ if (isstr(getarg(0)) == 1) {
+ .@val$ = getarg(0);
+ } else {
+ .@int = true;
+ .@val = getarg(0);
+ }
+
+ deletearray(getarg(0), 1); // shift left
+
+ return .@int ? .@val : .@val$;
+}
+
+
+
+// array_unshift(<array>, <value>)
+// adds <value> to the start of the array, while shifting right
+// returns the new size
+
+function script array_unshift {
+ .@size = getarraysize(getarg(0)) + 1;
+ array_pad(getarg(0), -(.@size - getarrayindex(getarg(0))), getarg(1));
+ return .@size;
+}
+
+
+
+// array_pop(<array>)
+// returns the last element of the array and removes it
+
+function script array_pop {
+ .@last = getarraysize(getarg(0)) - 1;
+
+ if (isstr(getelementofarray(getarg(0), .@last)) == 1) {
+ .@val$ = getelementofarray(getarg(0), .@last);
+ } else {
+ .@int = true;
+ .@val = getelementofarray(getarg(0), .@last);
+ }
+
+ deletearray(getelementofarray(getarg(0), .@last), 1);
+
+ return .@int ? .@val : .@val$;
+}
+
+
+
+// array_push(<array>, <value>)
+// adds <value> to the end of the array
+// returns the new size
+
+function script array_push {
+ .@size = getarraysize(getarg(0));
+ set(getelementofarray(getarg(0), .@size), getarg(1));
+ return .@size + 1;
+}
+
+
+
+// array_shuffle(<array>)
+// shuffles the array
+// uses the Durstenfeld implementation of the Fisher-Yates algorithm
+
+function script array_shuffle {
+ .@index = getarrayindex(getarg(0));
+ .@size = getarraysize(getarg(0)) - .@index;
+ freeloop(true);
+
+ for (.@i = .@size - 1; .@i >= .@index + 1; --.@i) {
+ swap(getelementofarray(getarg(0), rand(.@index, .@i)), getelementofarray(getarg(0), .@i));
+ }
+
+ freeloop(false);
+ return true;
+}
+
+
+
+// array_unique(<array>{, <threshold>})
+// allows entries to appear up to <threshold> in the array
+
+function script array_unique {
+ .@size = getarraysize(getarg(0));
+ .@max = getarg(1, 1);
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ .@count = 1;
+ for (.@e = .@i + 1; .@e < .@size; ++.@e) {
+ if (getelementofarray(getarg(0), .@i) == getelementofarray(getarg(0), .@e)) {
+ if (++.@count >= .@max) {
+ deletearray(getelementofarray(getarg(0), .@e), 1);
+ ++.@removed; // increase counter
+ --.@size; // reduce size
+ --.@e; // step back
+ }
+ }
+ }
+ }
+
+ freeloop(false);
+ return .@removed;
+}
+
+
+
+// array_diff(<array1>, <array2>{, <array>...}, <array>)
+// compares array1 against one or more other arrays and fills the last array
+// with the values in array1 that are not present in any of the other arrays
+// returns the number of entries not matching
+
+function script array_diff {
+ .@size = getarraysize(getarg(0));
+ .@index = getarrayindex(getarg(0));
+ freeloop(true);
+
+ for (.@a = 1; .@a < (getargcount() - 1); ++.@a) {
+ for (.@i = .@index; .@i < .@size; ++.@i) {
+ if (!array_exists(getarg(.@a), getelementofarray(getarg(0), .@i))) {
+ array_push(getarg(getargcount() - 1), getelementofarray(getarg(0), .@i));
+ ++.@count;
+ }
+ }
+ }
+
+ freeloop(false);
+ return .@count;
+}
+
+
+
+// array_filter(<array>, "<function>"{, <neq>})
+// filters the array using a callback function
+
+function script array_filter {
+ .@size = getarraysize(getarg(0));
+ .@neq = getarg(2, false);
+ freeloop(true);
+
+ for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) {
+ .@eq = callfunc(getarg(1), getelementofarray(getarg(0), .@i)) != false;
+ if ((.@neq && .@eq) || (!(.@neq) && !(.@eq))) {
+ deletearray(getelementofarray(getarg(0), .@i), 1); // shift left
+ ++.@count; // increase the counter
+ --.@size; // reduce the size
+ --.@i; // step back
+ }
+ }
+
+ freeloop(false);
+ return .@count;
+}
+
+
+
+// array_sort(<array>)
+// sorts the array in ascending order
+// uses the Lomuto implementation of the Quicksort algorithm
+
+function script array_sort {
+ callsub(S_Quicksort, getarg(0), getarrayindex(getarg(0)), getarraysize(getarg(0)) - 1);
+ return true;
+
+S_Quicksort:
+ if (getarg(1) < getarg(2)) {
+ .@p = callsub(S_Partition, getarg(0), getarg(1), getarg(2));
+ callsub(S_Quicksort, getarg(0), getarg(1), .@p - 1);
+ callsub(S_Quicksort, getarg(0), .@p + 1, getarg(2));
+ }
+ return true;
+
+S_Partition:
+ .@i = getarg(1) - 1;
+
+ freeloop(true);
+ for (.@j = getarg(1); .@j <= getarg(2) - 1; ++.@j) {
+ if (getelementofarray(getarg(0), .@j) < getelementofarray(getarg(0), getarg(2))) {
+ swap(getelementofarray(getarg(0), ++.@i), getelementofarray(getarg(0), .@j));
+ }
+ }
+ freeloop(false);
+
+ swap(getelementofarray(getarg(0), ++.@i), getelementofarray(getarg(0), getarg(2)));
+ return .@i;
+}
+
+
+
+// array_rsort(<array>)
+// sorts the array in descending order
+
+function script array_rsort {
+ return array_sort(getarg(0)) && array_reverse(getarg(0));
+}
diff --git a/npc/functions/asklanguage.txt b/npc/functions/asklanguage.txt
new file mode 100644
index 00000000..f0cbe0f8
--- /dev/null
+++ b/npc/functions/asklanguage.txt
@@ -0,0 +1,56 @@
+// Evol functions.
+// Author:
+// Reid
+// Description:
+// Function setting the player language
+
+function script asklanguage {
+
+ .@nb_language = 11;
+
+ switch (getarg(0, 0))
+ {
+ case LANG_ON_SEA:
+ setarray .@messages$[0], "I hear you... (English)", // English
+ "Je vous entends... (Français)", // French
+ "Te oigo... (Español)", // Spanish
+ "Ich höre euch... (Deutsch)"; // German
+ break;
+ case LANG_IN_SHIP:
+ setarray .@messages$[0], "I speak English.", // English
+ "Je parle français.", // French
+ "Hablo Español.", // Spanish
+ "Ich spreche Deutsch."; // German
+ break;
+ default:
+ return;
+ }
+
+ setarray .@flags$[0], "flags/en",
+ "flags/fr",
+ "flags/es",
+ "flags/de";
+
+ .@menustr$ = "";
+ .@separator$ = ":";
+
+ for (.@i = 0; .@i <= .@nb_language; .@i++)
+ {
+ if (.@i == .@nb_language)
+ {
+ .@separator$ = "";
+ }
+ .@menustr$ = .@menustr$ + .@flags$[.@i] + "|" + .@messages$[.@i] + .@separator$;
+ }
+
+ select(.@menustr$);
+
+ .@lang = @menu - 1;
+
+ if (.@lang >= 0 || .@lang <= .@nb_language)
+ {
+ Lang = .@lang;
+ }
+
+ return;
+}
diff --git a/npc/functions/asleep.txt b/npc/functions/asleep.txt
new file mode 100644
index 00000000..aa5abd63
--- /dev/null
+++ b/npc/functions/asleep.txt
@@ -0,0 +1,19 @@
+// Evol functions.
+// Authors:
+// Alige
+// Reid
+// Description:
+// Tell a random sleeping sound.
+// Variables:
+// .@rand = Random number between the number of "sleeping" choice.
+
+function script asleep {
+ switch(rand(5)) {
+ case 0: npctalkonce(l("Zzzzzzzzz...")); break;
+ case 1: npctalkonce(l("Rrrr... Pchhhh...")); break;
+ case 2: npctalkonce(l("Ggrmm... Grmmmm...")); break;
+ case 3: npctalkonce(l("Hm... Shhhh...")); break;
+ default: emotion(E_SLEEPY);
+ }
+ end;
+}
diff --git a/npc/functions/bank.txt b/npc/functions/bank.txt
new file mode 100644
index 00000000..2af9136e
--- /dev/null
+++ b/npc/functions/bank.txt
@@ -0,0 +1,297 @@
+// Evol scripts.
+// Authors:
+// gumi
+// Reid
+// Jesusalva
+
+function script MerchantGuild_Bank {
+ do
+ {
+ if (BankVault > 0)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You currently have @@ Esperin on your bank account.",
+ format_number(BankVault)),
+ l("What do you want to do with your money?");
+ }
+ else
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("What do you want to do with your money?");
+ }
+
+ select
+ rif(Zeny > 0, l("Deposit.")),
+ rif(BankVault > 0, l("Withdraw.")),
+ l("I'm done.");
+
+ switch (@menu)
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("How much do you want to deposit?");
+
+ menuint
+ l("Other."), -1,
+ rif(Zeny >= 5000, format_number(5000) + " E."), 5000,
+ rif(Zeny >= 10000, format_number(10000) + " E."), 10000,
+ rif(Zeny >= 25000, format_number(25000) + " E."), 25000,
+ rif(Zeny >= 50000, format_number(50000) + " E."), 50000,
+ rif(Zeny >= 100000, format_number(100000) + " E."), 100000,
+ rif(Zeny >= 250000, format_number(250000) + " E."), 250000,
+ rif(Zeny >= 500000, format_number(500000) + " E."), 500000,
+ rif(Zeny >= 1000000, format_number(1000000) + " E."), 1000000,
+ l("All of my money."), -2,
+ l("I changed my mind."), -3;
+
+ switch (@menuret)
+ {
+ case -1:
+ input @menuret;
+ break;
+ case -2:
+ @menuret = Zeny;
+ }
+
+ if (@menuret > 0)
+ {
+ if (@menuret > Zeny)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You do not have enough Esperin on yourself.");
+ break;
+ }
+
+ @menuret = min(MAX_BANK_ZENY, @menuret); // make sure the variable can't overflow
+ .@before = BankVault; // amount before the deposit
+ .@max = MAX_BANK_ZENY - BankVault; // maximum possible deposit
+ .@deposit = min(.@max, @menuret); // actual deposit
+
+ if (.@deposit > 0)
+ {
+ BankVault += .@deposit; // add to bank
+ Zeny -= .@deposit; // remove from inventory
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You made a cash deposit of @@ E.", format_number(.@deposit));
+ }
+ }
+ break;
+
+ case 2:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("How much do you want to withdraw?");
+
+ menuint
+ l("Other."), -1,
+ rif(BankVault >= 5000, format_number(5000) + " E."), 5000,
+ rif(BankVault >= 10000, format_number(10000) + " E."), 10000,
+ rif(BankVault >= 25000, format_number(25000) + " E."), 25000,
+ rif(BankVault >= 50000, format_number(50000) + " E."), 50000,
+ rif(BankVault >= 100000, format_number(100000) + " E."), 100000,
+ rif(BankVault >= 250000, format_number(250000) + " E."), 250000,
+ rif(BankVault >= 500000, format_number(500000) + " E."), 500000,
+ rif(BankVault >= 1000000, format_number(1000000) + " E."), 1000000,
+ l("All of my money."), -2,
+ l("I changed my mind."), -3;
+
+ switch (@menuret)
+ {
+ case -1:
+ input @menuret;
+ break;
+ case -2:
+ @menuret = BankVault;
+ }
+
+ if (@menuret > 0)
+ {
+ if (@menuret > BankVault)
+ {
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You do not have enough Esperin on your bank account.");
+ break;
+ }
+
+ @menuret = min(MAX_ZENY, @menuret); // make sure the variable can't overflow
+ .@before = Zeny; // amount before the withdrawal
+ .@max = MAX_ZENY - Zeny; // maximum possible withdrawal
+ .@withdrawal = min(.@max, @menuret); // actual withdrawal
+
+ if (.@withdrawal > 0)
+ {
+ Zeny += .@withdrawal; // add to inventory
+ BankVault -= .@withdrawal; // remove from bank
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You withdrew a total of @@ E.", format_number(.@withdrawal));
+ }
+ }
+ break;
+
+ default: return;
+ }
+ } while (true);
+}
+
+// MerchantGuild_Quests(.bankid)
+function script MerchantGuild_Quests {
+ mes "";
+ // Quest Type, Quest Data, Quest Timer
+ .@q=getq(General_MerchantRequest);
+ .@q2=getq2(General_MerchantRequest);
+ .@q3=getq3(General_MerchantRequest);
+ .@id=getarg(0);
+
+ // Cooldown
+ if (.@q3 > gettimetick(2)) {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("There are no tasks for you right now.");
+ mesc l("Please come back later, in %s.", FuzzyTime(.@q3));
+ next;
+ return;
+ }
+
+ // TODO: Submit/Abort current request
+ switch (.@q) {
+ case MERCQ_LETTER:
+ if (.@id == .@q2) {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("Thanks for the letter! Your efforts are greatly appreciated.");
+ Zeny+=rand2(100, 500);
+ getexp rand2(1000, 5000), rand2(150, 300);
+ setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+1800;
+ return;
+ }
+ else
+ {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("Current task: Deliver a letter to %s", $@BANK_TOWN$[.@q2]);
+ next;
+ select
+ l("Continue"),
+ l("Abort") + " ["+l("Change task")+"]";
+ mes "";
+ if (@menu == 1)
+ return;
+ setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2);
+ }
+ break;
+ /* ***************************************** */
+ case MERCQ_GOODS:
+ .@cont=ASK_NO;
+ if (countitem(.@q2)) {
+ mesc l("Deliver %s?", getitemlink(.@q2));
+ .@cont=askyesno();
+ }
+ if (.@cont == ASK_YES) {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("Thanks for the %s! Your efforts are greatly appreciated.", getitemlink(.@q2));
+ delitem .@q2, 1;
+ Zeny+=rand2(500, 2500);
+ getexp rand2(5000, 15000), rand2(250, 400);
+ setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+7200;
+ return;
+ }
+ else
+ {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("Current task: Purchase a(n) %s", getitemlink(.@q2));
+ next;
+ select
+ l("Continue"),
+ l("Abort") + " ["+l("Change task")+"]";
+ mes "";
+ if (@menu == 1)
+ return;
+ setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2);
+ }
+ break;
+ /* ***************************************** */
+ case MERCQ_SCOUT:
+ if (.@id == .@q2) {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("Thanks for scorting our caravan! Your efforts are greatly appreciated.");
+ Zeny+=rand2(2500, 5000);
+ getexp rand2(21000, 35000), rand2(500, 800);
+ setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+43200;
+ return;
+ }
+ else
+ {
+ mesn $@BANK_NAME$[.@id];
+ mesq l("Current task: Scout guild member to %s", $@BANK_TOWN$[.@q2]);
+ next;
+ select
+ l("Continue"),
+ l("Abort");
+ mes "";
+ if (@menu == 1)
+ return;
+ setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2);
+ }
+ break;
+ }
+
+ do
+ {
+ mesc l("The %s Merchant Guild has a few requests for you:", $@BANK_TOWN$[.@id]);
+ .@town = .@id;
+ while (.@town == .@id) {
+ .@town=rand2(getarraysize($@BANK_TOWN$));
+ }
+ select
+ l("How does this works?"),
+ rif(.@town != .@id, l("★ Deliver a letter")),
+ l("★★ Purchase goods"),
+ //rif(.@town != .@id, l("★★★ Scout a caravan")),
+ l("Sorry, I won't accept any.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ mesc l("The Merchant Guild spawns multiple continents, and we can offer you a few tasks for them. Be careful as you might not be able to finish them and you'll have to abort!");
+ mesc l("The more stars, the harder it is.");
+ next;
+ mesc l("After completing a request, there'll be a cooldown, proportional to the difficulty.");
+ mesc l("You can only have one Merchant Guild request active at same time.");
+ next;
+ break;
+ // Deliver a letter
+ case 2:
+ mesc l("We need you to deliver this important letter to %s! Avoid the roads and bandits!", $@BANK_NAME$[.@town]);
+ next;
+ mesc l("Accept request?");
+ if (askyesno() == ASK_YES) {
+ mesc l("I'm counting on you!");
+ setq General_MerchantRequest, MERCQ_LETTER, .@town, gettimetick(2);
+ return;
+ }
+ break;
+ // Purchase goods
+ case 3:
+ .@item=any(ElixirOfLife,
+ CarpSandwich, PioulegSandwich, MananaSandwich,
+ MaggotSlimePotion, BlueberryCake, CarrotCake, Donut,
+ DeathPotion, TreasureMap, IronIngot, SilverIngot, GoldIngot,
+ Diamond, Ruby, Emerald, Sapphire, Topaz, Amethyst,
+ CrudeDiamond, CrudeRuby, CrudeEmerald,
+ CrudeSapphire, CrudeTopaz, CrudeAmethyst,
+ RunestoneUruz, RunestoneRaido, RunestoneThurisaz,
+ RunestoneKaunaz, RunestoneDagaz, RunestonePeorth);
+ // TODO: equips, as crafting/tailoring is added
+ mesc l("The merchant guild needs %s! Purchase it and deliver at the nearest merchant guild member!", getitemlink(.@item));
+ next;
+ mesc l("Accept request?");
+ if (askyesno() == ASK_YES) {
+ mesc l("I'm counting on you!");
+ setq General_MerchantRequest, MERCQ_GOODS, .@item, gettimetick(2);
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ } while (true);
+ return;
+}
+
diff --git a/npc/functions/barber.txt b/npc/functions/barber.txt
new file mode 100644
index 00000000..d5a330f2
--- /dev/null
+++ b/npc/functions/barber.txt
@@ -0,0 +1,220 @@
+// Evol scripts.
+// Authors:
+// omatt
+// Reid
+// Travolta
+// Jesusalva
+// Description:
+// Function for supporting barber NPC.
+
+// BarberSayStyle({what})
+// what: 1 = Style; 2 = Color; 3 = Style + Color in dialog
+function script BarberSayStyle {
+
+ .@get_color = getlook(LOOK_HAIR_COLOR);
+ .@get_look = getlook(LOOK_HAIR);
+ .@style_name$ = $@hairstyle$[.@get_look];
+ .@color_name$ = $@haircolor$[.@get_color];
+
+ switch (getarg(0, 3))
+ {
+ case 1:
+ message strcharinfo(0), l("@@", .@style_name$);
+ break;
+ case 2:
+ message strcharinfo(0), l("@@", .@color_name$);
+ break;
+ case 3:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Your hairstyle is @@ and its color is @@.", .@style_name$, .@color_name$);
+ break;
+ }
+ return;
+}
+function script BarberChangeStyle {
+ do
+ {
+ .@hairsizearray = getarraysize($@hairstyle$);
+ .@get_look = getlook(LOOK_HAIR);
+
+ // Here .@i starts from 1 because hairstyle 0 doesn't exist.
+ for (.@i = 1; .@i < .@hairsizearray; .@i++)
+ {
+ .@menustr$ = .@menustr$
+ + rif(.@get_look != .@i, l("" + $@hairstyle$[.@i] + ""))
+ + ":";
+ }
+
+ .@menustr$ = .@menustr$ + l("I'm fine for now, thank you.");
+
+ .@idx = select(l("As you want!"),.@menustr$);
+
+ if (.@idx == .@i + 1) return; // last choice to quit dialog
+
+ switch (@menu)
+ {
+ case 1:
+ do
+ {
+ // here "- 1" because i don't use the 0 of array
+ .@rand_hair = rand(1,(.@hairsizearray - 1));
+ } while (.@rand_hair == getlook(LOOK_HAIR));
+ setlook LOOK_HAIR, .@rand_hair;
+ setlook LOOK_HAIR_COLOR, getlook(LOOK_HAIR_COLOR);
+ BarberSayStyle(1);
+ break;
+ default:
+ // and here "- 1" because the first choice is taken by the random
+ setlook LOOK_HAIR, (@menu - 1);
+ setlook LOOK_HAIR_COLOR, getlook(LOOK_HAIR_COLOR);
+ break;
+ }
+ .@menustr$ = "";
+ } while (1);
+}
+
+function script BarberChangeColor {
+ do
+ {
+ .@get_look = getlook(LOOK_HAIR_COLOR);
+ .@hairsizearray = getarraysize($@haircolor$);
+
+ for (.@i = 0; .@i < .@hairsizearray; .@i++)
+ {
+ .@menustr$ = .@menustr$
+ + rif(.@get_look != .@i, l("" + $@haircolor$[.@i] + ""))
+ + ":";
+ }
+
+ .@menustr$ = l("Surprise me!") + ":" + .@menustr$ + l("I'm fine for now, thank you.");
+
+ .@idx = select(.@menustr$);
+
+ if (.@idx == .@i + 2) return;
+
+ switch (@menu)
+ {
+ case 1:
+ do
+ {
+ .@rand_color = rand(0, .@hairsizearray);
+ } while (.@rand_color == getlook(LOOK_HAIR_COLOR));
+ setlook LOOK_HAIR_COLOR, .@rand_color;
+ BarberSayStyle(2);
+ break;
+ default:
+ setlook LOOK_HAIR_COLOR, (@menu - 2);
+ break;
+ }
+ .@menustr$ = "";
+ } while (1);
+
+ return;
+}
+
+function script BarberChangeBodyType {
+ mesn("Note");
+ mes(b(l("Changing your body type will send you back to the character selection screen.")));
+ next();
+
+ mes(l("Please select the desired body type:"));
+ menuint(
+ rif(BodyType == BODYTYPE_1, "► ") + l("Body type %i", 1), BODYTYPE_1,
+ rif(BodyType == BODYTYPE_2, "► ") + l("Body type %i", 2), BODYTYPE_2,
+ rif(BodyType == BODYTYPE_3, "► ") + l("Body type %i", 3), BODYTYPE_3);
+
+ if (BodyType == @menuret) {
+ return; // don't kick to char selection when not needed
+ }
+
+ // FIXME: when manaplus supports seamless changing for evol2, use a simple return;
+ closedialog();
+ close2();
+ BodyType = @menuret;
+ close;
+}
+
+// THIS FUNCTION SHOULD BE USED ONLY AT REBIRTH
+// Unless current game development design changes!
+function script BarberChangeRace {
+
+ mes l("What's your race?");
+ menuint
+ get_race(GETRACE_FULL, KaizeiTalpan), KaizeiTalpan,
+ get_race(GETRACE_FULL, ArgaesTalpan), ArgaesTalpan,
+ get_race(GETRACE_FULL, TonoriTalpan), TonoriTalpan,
+ get_race(GETRACE_FULL, CaveUkar), CaveUkar,
+ get_race(GETRACE_FULL, MountainUkar), MountainUkar,
+ get_race(GETRACE_FULL, SeaTritan), SeaTritan,
+ get_race(GETRACE_FULL, LakeTritan), LakeTritan,
+ rif(REBIRTH, get_race(GETRACE_FULL, LightRaijin)), LightRaijin,
+ rif(REBIRTH, get_race(GETRACE_FULL, DarkRaijin)), DarkRaijin,
+ rif(REBIRTH, get_race(GETRACE_FULL, FireKralog)), FireKralog,
+ rif(REBIRTH, get_race(GETRACE_FULL, FrostKralog)), FrostKralog;
+
+ mes "";
+ // Something went *terribly* wrong
+ if (@menuret >= LightRaijin && !REBIRTH) {
+ channelmes("#irc", "Illegal operation at BarberChangeRace, sysadmin help required.");
+ consolemes(CONSOLEMES_ERROR, "Account %d tried to change race to %d but rebirth is not set. Race not changed.", getcharid(3), @menuret);
+ return;
+ }
+
+ // Change race and we're done
+ //Class = @menuret;
+ jobchange(@menuret); // STUPID idea, but imposed by Hercules
+ return;
+}
+
+// Jack of all trades
+// Barber({intro=True})
+function script Barber {
+ if (getarg(0, true)) {
+ mesn;
+ mesq l("Hello.");
+ next;
+ }
+ mesq l("What would you like me to do?");
+ next;
+ do
+ {
+ select
+ l("What is my current hairstyle and hair color?"),
+ l("I'd like to get a different style."),
+ l("Can you do something with my color?"),
+ l("How about changing my body type?"),
+ l("I'm fine for now, thank you.");
+
+ switch (@menu)
+ {
+ case 1:
+ BarberSayStyle();
+ break;
+ case 2:
+ BarberChangeStyle;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Enjoy your new style."),
+ l("Anything else?");
+ break;
+ case 3:
+ BarberChangeColor;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I hope you like this color."),
+ l("Anything else?");
+ break;
+ case 4:
+ BarberChangeBodyType();
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You look fantastic."),
+ l("Anything else?");
+ break;
+ case 5:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Feel free to come visit me another time.");
+
+ goodbye;
+ }
+ } while (true);
+ return;
+}
+
diff --git a/npc/functions/beds.txt b/npc/functions/beds.txt
new file mode 100644
index 00000000..a4301891
--- /dev/null
+++ b/npc/functions/beds.txt
@@ -0,0 +1,22 @@
+// Evol functions.
+// Authors:
+// 4144
+// Reid
+// Jesusalva
+// Description:
+// Beds utility functions
+
+// bedTouch({inn})
+function script bedTouch {
+ if (PC_IS_DEAD)
+ {
+ PC_IS_DEAD = 0;
+ if (INN_REGISTER != NO_INN)
+ {
+ INN_REGISTER = NO_INN;
+ percentheal 100,100;
+ }
+ }
+ close;
+}
+
diff --git a/npc/functions/bitwise.txt b/npc/functions/bitwise.txt
new file mode 100644
index 00000000..a2e57587
--- /dev/null
+++ b/npc/functions/bitwise.txt
@@ -0,0 +1,66 @@
+/**
+ * Gets a bitmasked value in from an integer. If the shift is omitted, it will
+ * be deduced from the mask.
+ *
+ * @arg 0 - the variable
+ * @arg 1 - mask
+ * @arg 2 - shift
+ */
+function script bitwise_get {
+ .@shift = getarg(2, 0);
+
+ if (getargcount() < 3) {
+ // guess the shift from the mask:
+ for (.@shift = 0; .@shift < 32; ++.@shift) {
+ if ((getarg(1) & (1 << .@shift)) != 0) {
+ break;
+ }
+ }
+ }
+
+ return (getarg(0) & getarg(1)) >> .@shift;
+}
+
+/**
+ * sets a bitmasked value in a variable
+ *
+ * @arg 0 - the target variable
+ * @arg 1 - mask
+ * @arg 2 - shift
+ * @arg 3 - new value
+ * @return a reference to the variable
+ */
+function script bitwise_set {
+ if (getargcount() < 4) {
+ // guess the shift from the mask:
+ for (.@shift = 0; .@shift < 32; ++.@shift) {
+ if ((getarg(1) & (1 << .@shift)) != 0) {
+ break;
+ }
+ }
+
+ return set(getarg(0), (getarg(0) & ~(getarg(1))) | (getarg(2, 0) << .@shift));
+ }
+
+ return set(getarg(0), (getarg(0) & ~(getarg(1))) | (getarg(3, 0) << getarg(2, 0)));
+}
+
+
+// bitmask_count(<int>)
+// returns the number of bits set in <int> (up to 4096?)
+function script bitmask_count {
+ .@n = getarg(0); // Number evaluated
+ .@p=0; // Bits set/unset
+ .@s=0; // Stack and Check
+ .@m=0; // Memory
+
+ // Loop only as needed
+ while (.@s < .@n) {
+ .@s=2**.@m;
+ if (.@n & .@s)
+ .@p++;
+ .@m++;
+ }
+ return .@p;
+}
+
diff --git a/npc/functions/bodytype.txt b/npc/functions/bodytype.txt
new file mode 100644
index 00000000..5d37775a
--- /dev/null
+++ b/npc/functions/bodytype.txt
@@ -0,0 +1,19 @@
+function script stringToBodytype {
+ switch (ord(strtolower(charat(getarg(0, "n"), 0)))) {
+ case 50: // 2
+ case 102: // f
+ return BODYTYPE_2;
+ case 51: // 3
+ case 109: // m
+ return BODYTYPE_3;
+ default:
+ return BODYTYPE_1;
+ }
+}
+
+function script bodytypeToString {
+ .@bodytype = getarg(0, BodyType);
+
+ return .@bodytype == BODYTYPE_2 ? l("type %i", 2) :
+ .@bodytype == BODYTYPE_3 ? l("type %i", 3) : l("type %i", 1);
+}
diff --git a/npc/functions/casino.txt b/npc/functions/casino.txt
new file mode 100644
index 00000000..87b71a4d
--- /dev/null
+++ b/npc/functions/casino.txt
@@ -0,0 +1,254 @@
+// TMW2 Scripts
+// Author:
+// Jesusalva
+// Description:
+// Slot Machines, Blackjack, other crap for npc duplication
+// Contents:
+// "Slot Machine"
+// "High Lower"
+
+// SLOT MACHINE - You'll get PRIZE if you roll a 777!
+// PRIZE must be numeric INT, AegisName won't get parsed.
+// Slot Machine#map_prize
+// Slot Machine#map
+// Slot Machine#_prize
+- script Slot Machine NPC_HIDDEN,{
+ function symbol {
+ switch (getarg(0)) {
+ case 1:
+ mesn "%%A";
+ break;
+ case 2:
+ mesn "%%B";
+ break;
+ case 3:
+ mesn "%%C";
+ break;
+ case 4:
+ mesn "%%D";
+ break;
+ case 5:
+ mesn "%%E";
+ break;
+ case 6:
+ mesn "%%F";
+ break;
+ case 7:
+ mesn "7";
+ break;
+ default:
+ mesn "%%@";
+ break;
+ }
+ }
+
+L_Menu:
+ mesn;
+ mesc l("Spin three symbols, and jackpot great rewards!");
+ mesc l("Just one coin for spin.");
+ next;
+ menu
+ rif(countitem(.coinid) >= 1, l("Spin!")), L_Spin,
+ l("Prizes"), L_Info,
+ l("Leave"), -;
+ close;
+
+L_Info:
+ mes "";
+ mesc l("Prizes:");
+ mes l("##9 777: @@.", getitemlink(.itemid));
+ mesc l("Three equal: @@.", "18 casino coins");
+ mesc l("Two equal: 1 casino coin.");
+ next;
+ goto L_Menu;
+
+
+L_Spin:
+ mesc l("Spinning...");
+ next;
+ delitem .coinid, 1;
+ .@a=rand2(1,7);
+ .@b=rand2(1,7);
+ .@c=rand2(1,7);
+ symbol(.@a);
+ symbol(.@b);
+ symbol(.@c);
+ next;
+ mesn;
+ if (.@a == .@b && .@a == .@c && .@a == 7) {
+ getitem .itemid, 1;
+ mesc l("Jackpot! You got a(n) %s!", getitemlink(.itemid)), 3;
+ } else if (.@a == .@b && .@a == .@c) {
+ getitem .coinid, 18;
+ mesc l("Congrats! A pity it was not 777..."), 3;
+ } else if (.@a == .@b || .@a == .@c || .@b == .@c) {
+ getitem .coinid, 1;
+ mesc l("Lucky! You got the coin back!"), 3;
+ } else {
+ mesc l("It wasn't this time..."), 3;
+ }
+ next;
+ goto L_Menu;
+
+OnInit:
+ // "Next-Generation" parsing system
+ // To replace default item, name NPC like this:
+ // Slot Machine#_1212
+ // Where "1212" is the item ID
+ .@n$=strnpcinfo(0, "_0");
+ explode(.@ni$, .@n$, "_");
+ if (getarraysize(.@n$) > 0)
+ .itemid=atoi(.@ni$[1]);
+ else
+ .itemid=0;
+
+ // If item ID was not provided
+ if (.itemid < 1) {
+ //.itemid=Monocle;
+ .itemid=BrownBowlerHat;
+ }
+
+ // Coin ID
+ //.coinid=CasinoCoins;
+ .coinid=CoinBag;
+
+ .sex = G_OTHER;
+ .distance = 4;
+ end;
+}
+
+
+// HIGH LOWER - Guess if the next card will be HIGHER or LOWER!
+// (No arguments)
+- script High Lower NPC_HIDDEN,{
+ function cardname {
+ switch (getarg(0)) {
+ case 0:
+ return "A"; break;
+ case 10:
+ return "J"; break;
+ case 11:
+ return "Q"; break;
+ case 12:
+ return "K"; break;
+ case 13:
+ return l("Joker"); break;
+ default:
+ return getarg(0)+1;
+ }
+ }
+
+ goto L_Menu;
+
+L_Menu:
+ showavatar;
+ mesn;
+ mesc l("Hey, I am flopped. Do you want to gamble?");
+ mesc l("You need a %s. I'll flip one card, and you'll need to decide if next draw will be HIGHER or LOWER.", getitemlink(.coinid));
+ mesc l("If a tie happens, I'll give your coin back.");
+ next;
+ menu
+ rif(countitem(.coinid) >= 1, l("Let's play!")), L_Spin,
+ l("Information"), L_Info,
+ l("Leave"), L_Quit;
+
+L_Info:
+ mes "";
+ mesc l("Rules:");
+ mesc l("A card will be flipped, you'll need to decide if next flip will be HIGHER or LOWER.");
+ mesc l("Cards are ranked on this priority: A - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - J - Q - K - Joker");
+ next;
+ mesc l("Prizes:");
+ mesc l("If you're right, you'll get at least %d GP!", .minprize);
+ mesc l("If a tie happens, you'll get your coin back.");
+ mesc l("If you're wrong, your winning streak is reset.");
+ mesc l("Winning Streak is also reset on logout or when you leave the room.");
+ next;
+ mesc l("Winning Strike Prizes:");
+ mesc l("Every seven successive right guesses, you'll get a %s!", getitemlink(Acorn)); // 7.14%
+ //mesc l("Every fifteen successive right guesses, you'll get a %s!", getitemlink(SilverGift)); // 3.33%
+ //mesc l("Every fifty successive right guesses, you'll get a %s!", getitemlink(GoldenGift)); // 1.00%
+ //mesc l("Every 101 successive right guesses, you'll get a %s!", getitemlink(PrismGift)); // 0.50%
+ next;
+ goto L_Menu;
+
+
+L_Spin:
+ showavatar AVATAR_CARD_COVER;
+ mesc l("I'll draw a card now!");
+ next;
+ delitem .coinid, 1;
+ // First card will never be an edge card (Ace or Joker), so you can ALWAYS guess wrong.
+ .@card1=rand2(1, 12);
+ showavatar 1000+.@card1;
+ mesn;
+ mesc l("It's a @@!", cardname(.@card1));
+ mesc l("Will next draw be HIGHER or LOWER?!");
+ next;
+ mesc l("Cards are ranked on this priority: A - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - J - Q - K - Joker");
+ select
+ l("HIGHER!"),
+ l("LOWER!");
+ mes "";
+
+ // Flip Flop!
+ .@card2=rand2(0, 13);
+ showavatar 1000+.@card2;
+ mesn;
+ mesc l("It's a @@!", cardname(.@card2));
+
+ if (.@card1 == .@card2) {
+ mesc l("It's a tie!");
+ getitem .coinid, 1;
+ .@bypass=1;
+ } else if (.@card2 < .@card1 && @menu == 2) {
+ mesc l("It's lower! That's right!");
+ Zeny=Zeny+.minprize;
+ @gambler_winstreak+=1;
+ } else if (.@card2 > .@card1 && @menu == 1) {
+ mesc l("It's higher! That's right!");
+ Zeny=Zeny+.minprize;
+ @gambler_winstreak+=1;
+ } else {
+ mesc l("You were wrong!");
+ @gambler_winstreak=0;
+ }
+
+ // Winning Streak
+ if (!.@bypass && @gambler_winstreak) {
+ if (@gambler_winstreak % 7 == 0)
+ getitem Acorn, 1;
+ /*
+ if (@gambler_winstreak % 15 == 0)
+ getitem SilverGift, 1;
+ if (@gambler_winstreak % 50 == 0)
+ getitem GoldenGift, 1;
+ if (@gambler_winstreak % 101 == 0)
+ getitem PrismGift, 1;
+ */
+ mesc l("Your current win streak is @@!", @gambler_winstreak);
+ Zeny+=min(((@gambler_winstreak-1)*.gpbonus), .minprize); // Never 2x
+ } else {
+ .@bypass=0;
+ }
+ next;
+ goto L_Menu;
+
+L_Quit:
+ close;
+
+OnInit:
+ // Gambling configuration
+ .minprize=180;
+ .gpbonus=10;
+
+ // Coin ID
+ //.coinid=CasinoCoins;
+ .coinid=CoinBag;
+
+ .sex = G_OTHER;
+ .distance = 4;
+ end;
+
+}
+
diff --git a/npc/functions/clientversion.txt b/npc/functions/clientversion.txt
new file mode 100644
index 00000000..2f097e4e
--- /dev/null
+++ b/npc/functions/clientversion.txt
@@ -0,0 +1,20 @@
+// Evol functions.
+// Author:
+// 4144
+// Description:
+// Function checking the client version and reports if it is too old.
+
+function script checkclientversion {
+ if (ClientVersion > 23) return;
+
+ mesn "Narrator";
+ mes col("Warning.", 9);
+ mes col("Warning.", 9);
+ mes col("Warning: You are using an old client.", 9);
+ next;
+ mes col("Not all features will work.", 9);
+ next;
+ mesc l("Please install the new client from %s.", "[@@https://manaplus.org/|@@]");
+ next;
+ return;
+}
diff --git a/npc/functions/confused-tree-dict.txt b/npc/functions/confused-tree-dict.txt
new file mode 100644
index 00000000..138c4704
--- /dev/null
+++ b/npc/functions/confused-tree-dict.txt
@@ -0,0 +1,515 @@
+// Evol scripts.
+// Author:
+// gumi
+// rein
+// Based on CrazyTree, originally made by:
+// gumi
+// pclouds
+// veryape
+// wushin
+// Description:
+// dictionaries for confused tree
+
+// Built-in variables:
+// ~t lowercase hot word regex
+// ~n npc name
+// ~p player name or special name
+// ~P player name only
+//
+// Custom variables:
+// {{var}} random from array .D_var$
+// {{^var}} same but capitalize
+// {{+var}} same but title case
+// {{!var}} same but all caps
+// You can also specify multiple variables, separated by a comma (,)
+//
+// Example:
+// "*drops a {{! size }} {{ color }} {{^ sizeable object, someone }} on ~p's head*"
+
+function script TREE_dictionaries {
+ .npc$ = strnpcinfo(0);
+
+ // special aliases below (regex of lowercase char names)
+ // the substitutions are an array separated by backticks (`)
+ // XXX: this could become a hashtable at some point if it gets too big
+
+ setarray(getvariableofnpc(.alias$[0], .npc$),
+ "^veryape(?:gm)?$", "hairyape",
+
+ "^wu-?shin$", "Dwarven Princess`"
+ "She-Ra",
+
+ "^reid$", "Borg Queen`"
+ "Mistress`"
+ "Milady`"
+ "R'eid",
+
+ "^(?:slicer|madcamel)$", "Camel Toe",
+
+ "^4144(?:4d494e)?$", "NPC",
+
+ "^omatt$", "@@https://youtu.be/S2qiZoqH9OY|omatt@@`"
+ "o'matt",
+
+ "^prsm$", "Refractor`"
+ "Overlord");
+ set(getvariableofnpc(.alias, .npc$), getarraysize(getvariableofnpc(.alias$, .npc$)));
+
+
+
+ // special drops below (regex of lowercase char names)
+ // the substitutions are an array of standard replies separated by backticks (`)
+ // and allow {{variables}}
+ // XXX: this could become a hashtable at some point if it gets too big
+
+ setarray(getvariableofnpc(.sdrops$[0], .npc$),
+ "^reid$", "*drops an empty jar of Nutella on ~p*",
+ "^omatt$", "*drops Elisabeth Granneman on ~p*");
+ set(getvariableofnpc(.sdrops, .npc$), getarraysize(getvariableofnpc(.sdrops$, .npc$)));
+
+
+ // variables below
+
+ setarray(getvariableofnpc(.D_size$[1], .npc$), // {{size}}
+ "tiny", 1,
+ "small", 1,
+ "perfectly sized", 1,
+ "large", 1,
+ "huge", 1,
+ "humongous", 1,
+ "ginormous", 1);
+ set(getvariableofnpc(.D_size, .npc$), getarraysize(getvariableofnpc(.D_size$, .npc$)));
+
+ setarray(getvariableofnpc(.D_color$[1], .npc$), // {{color}}
+ "red", 1,
+ "orange", 1,
+ "yellow", 1,
+ "pink", 1,
+ "aqua", 1,
+ "cyan", 1,
+ "blue", 1,
+ "indigo", 1,
+ "violet", 1,
+ "purple", 1,
+ "magenta", 1,
+ "pink", 1,
+ "black", 1,
+ "white", 1,
+ "grey", 1,
+ "greyscale", 1,
+ "brown", 1,
+ "maroon", 1,
+ "turquoise", 1,
+ "lime", 1,
+ "sky blue", 1,
+ "invisible", 1);
+ set(getvariableofnpc(.D_color, .npc$), getarraysize(getvariableofnpc(.D_color$, .npc$)));
+
+ setarray(getvariableofnpc(.D_violentadverb$[1], .npc$), // {{violent adverb}}
+ "violently", 1,
+ "repeatedly", 1,
+ "casually", 1,
+ "forcefully", 1,
+ "slowly", 1,
+ "carefully", 1,
+ "hopefully", 1,
+ "dangerously", 1,
+ "shockingly", 1,
+ "religiously", 1);
+ set(getvariableofnpc(.D_violentadverb, .npc$), getarraysize(getvariableofnpc(.D_violentadverb$, .npc$)));
+
+ setarray(getvariableofnpc(.D_hello$[1], .npc$), // {{hello}}
+ "hi", 4,
+ "hey", 3,
+ "yo", 2,
+ "hello", 10,
+ "howdy", 1,
+ "bonjour", 1);
+ set(getvariableofnpc(.D_hello, .npc$), getarraysize(getvariableofnpc(.D_hello$, .npc$)));
+
+ setarray(getvariableofnpc(.D_violentverb$[1], .npc$), // {{violent verb}}
+ "slaps", 5,
+ "hits", 1,
+ "pummels", 1,
+ "beats", 1,
+ "flattens", 1,
+ "taunts", 1,
+ "liquidates", 1,
+ "spanks", 1,
+ "affronts", 1,
+ "tranquilizes", 1,
+ "atomizes", 1,
+ "impales", 1,
+ "dismembers", 1);
+ set(getvariableofnpc(.D_violentverb, .npc$), getarraysize(getvariableofnpc(.D_violentverb$, .npc$)));
+
+ setarray(getvariableofnpc(.D_location$[1], .npc$), // {{location}}
+ "Artis", 1,
+ "Hurnscald", 1,
+ "Tulimshar", 1,
+ "Nivalis", 1,
+ "Candor", 1,
+ "Drasil", 1);
+ set(getvariableofnpc(.D_location, .npc$), getarraysize(getvariableofnpc(.D_location$, .npc$)));
+
+ setarray(getvariableofnpc(.D_sizeableobject$[1], .npc$), // {{sizeable object}}
+ "trout", 1,
+ "whale", 1,
+ "space whale", 1,
+ "penguin", 1,
+ "coelacanth", 1,
+ "squid", 1,
+ "shrimp", 1,
+ "crab", 1,
+ "tentacle", 1,
+ "dictionary", 1,
+ "grammar book", 1,
+ "textbook", 1,
+ "dinosaur", 1,
+ "t-rex", 1,
+ "star-nosed mole", 1,
+ "chimpanzee", 1,
+ "mermaid", 1,
+ "merman", 1,
+ "piano", 1,
+ "prince", 1,
+ "princess", 1,
+ "pinkie", 1,
+ "squirrel", 1,
+ "mouboo", 1,
+ "wet mop", 1,
+ "drunken pirate", 1,
+ "cake", 1,
+ "cookie", 1,
+ "chocobo", 1,
+ "restraining order", 1,
+ "freight train", 1,
+ "carnival hammer", 1,
+ "crate", 1,
+ "bomb", 1,
+ "bowl of petinuas", 1,
+ "box", 1,
+ "platypus", 1,
+ "magic eightball", 1,
+ "vase", 1);
+ set(getvariableofnpc(.D_sizeableobject, .npc$), getarraysize(getvariableofnpc(.D_sizeableobject$, .npc$)));
+
+ setarray(getvariableofnpc(.D_nsizeableobject$[1], .npc$), // {{n sizeable object}}
+ "octopus", 1,
+ "elephant", 1,
+ "angry cat", 1,
+ "anvil", 1,
+ "encyclopedia set", 1);
+ set(getvariableofnpc(.D_nsizeableobject, .npc$), getarraysize(getvariableofnpc(.D_nsizeableobject$, .npc$)));
+
+ setarray(getvariableofnpc(.D_someone$[1], .npc$), // {{someone}}
+ "Voldemort", 1,
+ "Cthulhu", 1,
+ "Platyna", 1,
+ "Hitler", 1,
+ "Luvia", 1,
+ "General Krukan", 1,
+ "Borg Queen", 1,
+ "Freeyorp", 1,
+ "MadCamel", 1);
+ set(getvariableofnpc(.D_someone, .npc$), getarraysize(getvariableofnpc(.D_someone$, .npc$)));
+
+ // replies below
+
+ setarray(getvariableofnpc(.greetings$[1], .npc$),
+ "{{^ hello }} ~p!", 4,
+ "{{^ hello }} ~p.", 6,
+ "{{^ hello }} ~p, what's up?", 1,
+ "{{^ hello }} ~p, anything new?", 1,
+ "{{^ hello }} ~p, how are you?", 1,
+ "~p!!!!", 1,
+ "~p!!!", 1,
+ "~p!!", 1,
+ "{{^ hello }} ~p! You are looking lovely today!", 1,
+ "Welcome back, ~p.", 3,
+ "~p is back!!", 1,
+ "Hello and welcome to the Aperture Science computer-aided enrichment center.", 1,
+ "Greetings ~p.", 1,
+ "What's up ~p?", 2,
+ "How are you ~p?", 1);
+ set(getvariableofnpc(.greetings, .npc$), getarraysize(getvariableofnpc(.greetings$, .npc$)));
+
+ setarray(getvariableofnpc(.jokes$[1], .npc$),
+ "How did the tree get drunk? On root beer.", 1,
+ "Do you think I'm lazy?", 1,
+ "I miss CrazyTree %%S.", 1,
+ "I miss LazyTree %%S.", 1,
+ "I'm not telling you!", 1,
+ "*sighs.*", 1,
+ "If I do it for you, then I have to do it for everybody.", 1,
+ "What did the beaver say to the tree? It's been nice gnawing you.", 1,
+ "What did the little tree say to the big tree? Leaf me alone.", 1,
+ "What did the tree wear to the pool party? Swimming trunks.", 1,
+ "What do trees give to their dogs? Treets.", 1,
+ "What do you call a tree that only eats meat? Carniforous.", 1,
+ "What do you call a tree who's always envious? Evergreen.", 1,
+ "What is the tree's least favourite month? Sep-timber!", 1,
+ "What kind of tree can fit into your hand? A palm-tree.", 1,
+ "What was the tree's favorite subject in school? Chemistree.", 1,
+ "Why did the leaf go to the doctor? It was feeling green.", 1,
+ "Why doesn't the tree need sudo? Because it has root.", 1,
+ "Why was the cat afraid of the tree? Because of its bark.", 1,
+ "Why was the tree executed? For treeson.", 1,
+ "How do trees get on the internet? They log in.", 1,
+ "Why did the pine tree get into trouble? Because it was being knotty.", 1,
+ "Did you hear the one about the oak tree? It's a corn-y one!", 1,
+ "What do you call a blonde in a tree with a briefcase? Branch Manager.", 1,
+ "How is an apple like a lawyer? They both look good hanging from a tree.", 1,
+ "Why did the sheriff arrest the tree? Because its leaves rustled.", 1,
+ "I'm too tired, ask someone else.", 1,
+ "If you are trying to get me to tell jokes you are barking up the wrong tree!", 1,
+ "You wooden think they were funny anyhow. Leaf me alone!", 1,
+ "What is brown and sticky? A stick.", 1,
+ "What's the best way to carve wood? Whittle by whittle.", 1,
+ "What did the tree do when the bank closed? It started its own branch.", 1,
+ "Do you want a brief explanation of an acorn? In a nutshell, it’s an oak tree.", 1,
+ "A snare drum and a crash cymbal fell out of a tree. *BA-DUM TSSSHH*", 1,
+ "How do you properly identify a dogwood tree? By the bark!", 1,
+ "Where do saplings go to learn? Elementree school.", 1,
+ "Why do trees make great thieves? Sticky fingers.", 1,
+ "What is green, has leaves, and a trunk? A houseplant going on vacation.", 1,
+ "Where can Adansonia trees go for a quick trim? To the baobarber.", 1,
+ "What looks like half a spruce tree? The other half.", 1,
+ "What do you give to a sick citrus tree? Lemon aid.", 1,
+ "What did the tree say to the drill? You bore me.", 1,
+ "What happened to the wooden car with wooden wheels and a wooden engine? It wooden go.", 1,
+ "How do trees keep you in suspense? I'll tell you tomorrow.", 1,
+ "Where do birch trees keep their valuables? In a river bank.", 1,
+ "What kind of stories do giant sequoia trees tell? Tall tales.", 1,
+ "What is the most frustrating thing about being a tree? Having so many limbs and not being able to walk.", 1,
+ "What's black, highly dangerous, and lives in a tree? A crow with a machine gun.", 1,
+ "What kind of wood doesn't float? Natalie Wood.", 1,
+ "Two men passed a sign while looking for work. It was for tree fellers. They said: “what a shame, there are only two of us”.", 1);
+ set(getvariableofnpc(.jokes, .npc$), getarraysize(getvariableofnpc(.jokes$, .npc$)));
+
+ setarray(getvariableofnpc(.healing$[1], .npc$),
+ "Eat an apple, they're good for you.", 1,
+ "If I do it for you, then I have to do it for everybody.", 1,
+ "Oh, go drink a potion or something.", 1,
+ "Whoops! I lost my spellbook.", 1,
+ "No mana.", 1);
+ set(getvariableofnpc(.healing, .npc$), getarraysize(getvariableofnpc(.healing$, .npc$)));
+
+ setarray(getvariableofnpc(.whoami$[1], .npc$),
+ "An undercover GM.", 1,
+ "An exiled GM.", 1,
+ "I'm not telling you!", 1,
+ "I'm a bot! I'll be level 99 one day! Mwahahahaaha!!!111!", 1,
+ "Somebody said I'm a Chinese copy of CrazyTree.", 1,
+ "I am your evil twin.", 1,
+ "I don't remember anything after I woke up! What happened to me?", 1,
+ "I don't know. Why am I here??", 1,
+ "Who are you?", 1,
+ "On the 8th day, God was bored and said 'There will be bots'. So here I am.", 1,
+ "♪ I'm your hell, I'm your dream, I'm nothing in between ♪♪", 1,
+ "♪♪ Aperture Science. We do what we must, because... we can ♪", 1,
+ "I'm just a reincarnation of a copy.", 1);
+ set(getvariableofnpc(.whoami, .npc$), getarraysize(getvariableofnpc(.whoami$, .npc$)));
+
+ setarray(getvariableofnpc(.drops$[1], .npc$),
+ "*drops a {{ sizeable object }} on ~p's head.*", 8,
+ "*drops an {{ n sizeable object }} on ~p's head.*", 2,
+ "*drops {{ someone }} on ~p's head.*", 1,
+ "*drops a coin on ~p's head.*", 1,
+ "*drops a fruit on ~p's head.*", 1,
+ "*drops an apple on ~p's head.*", 1,
+ "*drops an iten on ~p's head.*", 1,
+ "*drops a GM on ~p.*", 1,
+ "*drops a piece of moon rock on ~p's head.*", 1,
+ "*drops a pin on ~p's head.*", 1,
+ "*drops a rock on ~p's head.*", 1,
+ "*drops a tub of paint on ~p's head.*", 1,
+ "*drops a sandworm on ~p.*", 1,
+ "*drops an idea in ~p's head.*", 1,
+ "*drops The Hitchhiker's Guide to the Galaxy on ~p's head.*", 1,
+ "Ouch.", 1,
+ "Ouchy.", 1,
+ "*drops dead.*", 1,
+ "*sighs.*", 1,
+ "Leaf me alone.", 1,
+ "Stop it! I don't drop branches, try the Druid tree for once!", 1);
+ set(getvariableofnpc(.drops, .npc$), getarraysize(getvariableofnpc(.drops$, .npc$)));
+
+ setarray(getvariableofnpc(.die$[1], .npc$),
+ "*drops an iten on ~p's head.*", 1,
+ "*drops a piece of moon rock on ~p's head.*", 1,
+ "*drops {{ someone }} on ~p's head.*", 1,
+ "*drops a {{ sizeable object }} on ~p's head.*", 3,
+ "*drops an {{ n sizeable object }} on ~p's head.*", 1,
+ "*drops a {{ size }} {{ sizeable object, n sizeable object }} on ~p's head.*", 1,
+ "*drops a {{ size }} {{ color }} {{ sizeable object, n sizeable object }} on ~p's head.*", 1,
+ "*{{ violent adverb }} {{ violent verb }} ~p.*", 1,
+ "*drops dead.*", 1,
+ "*sighs.*", 1,
+ "Avada Kedavra!", 1,
+ "Make me!", 1,
+ "Never!!", 1,
+ "You die, ~p!", 4,
+ "No!", 1,
+ "In a minute.", 1,
+ "Suuure... I'll get right on it...", 1);
+ set(getvariableofnpc(.die, .npc$), getarraysize(getvariableofnpc(.die$, .npc$)));
+
+ setarray(getvariableofnpc(.poke$[1], .npc$),
+ "*tickles.*", 1);
+ set(getvariableofnpc(.poke, .npc$), getarraysize(getvariableofnpc(.poke$, .npc$)));
+
+ setarray(getvariableofnpc(.disgusting$[1], .npc$),
+ "Ewwwww %%^.", 1);
+ set(getvariableofnpc(.disgusting, .npc$), getarraysize(getvariableofnpc(.disgusting$, .npc$)));
+
+ setarray(getvariableofnpc(.answer$[1], .npc$),
+ "42.", 1,
+ "Kittens.", 1);
+ set(getvariableofnpc(.answer, .npc$), getarraysize(getvariableofnpc(.answer$, .npc$)));
+
+ setarray(getvariableofnpc(.burning$[1], .npc$),
+ "*curses ~p and dies %%c.*", 1,
+ "Help! I'm on fire!", 1,
+ "Oh hot.. hot hot!", 1,
+ "*is glowing.*", 1,
+ "*is flaming.*", 1,
+ "Ehemm. Where are firefighters? I need them now!", 1,
+ "*is so hot!.*", 1,
+ "*slowly catches fire.*", 1,
+ "*trembles with trepidation.*", 1,
+ "*is immune to fire.*", 1);
+ set(getvariableofnpc(.burning, .npc$), getarraysize(getvariableofnpc(.burning$, .npc$)));
+
+ setarray(getvariableofnpc(.kill$[1], .npc$),
+ "*curses ~p and dies %%c.*", 1);
+ set(getvariableofnpc(.kill, .npc$), getarraysize(getvariableofnpc(.kill$, .npc$)));
+
+ setarray(getvariableofnpc(.silly$[1], .npc$),
+ "Hahaha, good one!", 1);
+ set(getvariableofnpc(.silly, .npc$), getarraysize(getvariableofnpc(.silly$, .npc$)));
+
+ setarray(getvariableofnpc(.love$[1], .npc$),
+ "♪♪ and IIII.. will alwayyyys loooovvve youuuuu. ♪♪ %%]", 1,
+ "♪♪ nothing's gonna change my love for you, you oughta know by now how much I love you.. ♪ %%]", 1,
+ "♪ ..and then I go and spoil it all, by saying something stupid like: “I love you.” ♪", 1,
+ "♪ ..won't you find a place for me? somewhere in your heart... ♪♪", 1,
+ "Thank you.", 1,
+ "♪♪ ..I can't love another when my heart is somewhere far away.. ♪", 1,
+ "%%]", 1);
+ set(getvariableofnpc(.love, .npc$), getarraysize(getvariableofnpc(.love$, .npc$)));
+
+ setarray(getvariableofnpc(.dance$[1], .npc$),
+ "I would but I am rooted to the ground.", 1,
+ "Have you ever seen a tree dance before?", 1,
+ "Hahaha, good one!", 1);
+ set(getvariableofnpc(.dance, .npc$), getarraysize(getvariableofnpc(.dance$, .npc$)));
+
+ setarray(getvariableofnpc(.hate$[1], .npc$),
+ "Right back at you!", 1,
+ "Ok...", 1,
+ "*pats ~p, let it go...*", 1,
+ "Hu hu hu, ~p hates me.", 1);
+ set(getvariableofnpc(.hate, .npc$), getarraysize(getvariableofnpc(.hate$, .npc$)));
+
+ setarray(getvariableofnpc(.bye$[1], .npc$),
+ "*waves goodbye to ~p in tears, come back soon!*", 1);
+ set(getvariableofnpc(.bye, .npc$), getarraysize(getvariableofnpc(.bye$, .npc$)));
+
+ setarray(getvariableofnpc(.pain$[1], .npc$),
+ "Ouch.", 1,
+ "Ouchy.", 1,
+ "Argh.", 1,
+ "Eek.", 1,
+ "*howls.*", 1,
+ "*screams.*", 1,
+ "*groans.*", 1,
+ "*cries.*", 1,
+ "*faints.*", 1,
+ "*shrieks.*", 1,
+ "*hides behind itself.*", 1,
+ "%%k", 1,
+ "Why, what did I do to you? %%i", 1);
+ set(getvariableofnpc(.pain, .npc$), getarraysize(getvariableofnpc(.pain$, .npc$)));
+
+ setarray(getvariableofnpc(.eightball$[1], .npc$),
+ "It is possible.", 1,
+ "Yes!", 1,
+ "Of course.", 1,
+ "Naturally.", 1,
+ "Obviously.", 1,
+ "It shall be.", 1,
+ "The outlook is good.", 1,
+ "It is so.", 1,
+ "One would be wise to think so.", 1,
+ "The answer is certainly yes.", 1,
+ "In your dreams.", 1,
+ "I doubt it very much.", 1,
+ "No chance.", 1,
+ "The outlook is very poor.", 1,
+ "Unlikely.", 1,
+ "About as likely as pigs flying.", 1,
+ "You're kidding, right?", 1,
+ "NO!", 1,
+ "NO.", 1,
+ "No.", 1,
+ "Maybe...", 1,
+ "No clue.", 1,
+ "I don't know.", 1,
+ "The outlook is hazy, please ask again later.", 1,
+ "What are you asking me for?", 1,
+ "Come again?", 1,
+ "You know the answer better than I.", 1,
+ "The answer is def-- oooh! shiny thing!", 1,
+ "No idea.", 1,
+ "Perhaps.", 1,
+ "I think it is better not to tell you.", 1,
+ "Error 417: Expectation failed.", 1);
+ set(getvariableofnpc(.eightball, .npc$), getarraysize(getvariableofnpc(.eightball$, .npc$)));
+
+ setarray(getvariableofnpc(.bad$[1], .npc$),
+ "I'm not bad! You are bad!", 1,
+ "OK, I'm bad.", 1,
+ "I'm just a littttle bad.", 1,
+ "Not as bad as the people that made me.", 1);
+ set(getvariableofnpc(.bad, .npc$), getarraysize(getvariableofnpc(.bad$, .npc$)));
+
+ setarray(getvariableofnpc(.no_idea$[1], .npc$),
+ "What?", 2,
+ "What??", 1,
+ "Whatever.", 1,
+ "Hmm...", 2,
+ "Huh?", 1,
+ "*yawns.*", 1,
+ "Wait a minute...", 1,
+ "What are you talking about?", 1,
+ "Who are you?", 1,
+ "What about me?", 1,
+ "I don't know what you are talking about", 1,
+ "Excuse me?", 1,
+ "Very interesting.", 1,
+ "Really?", 1,
+ "Go on...", 1,
+ "*scratches its leafy head.*", 1,
+ "*feels a disturbance in the force.*", 1,
+ "%%j", 1,
+ "*senses a disturbance in the force.*", 1,
+ "I'm bored...", 1,
+ "%%U", 1,
+ "%%[", 1);
+ set(getvariableofnpc(.no_idea, .npc$), getarraysize(getvariableofnpc(.no_idea$, .npc$)));
+
+ setarray(getvariableofnpc(.shut_up$[1], .npc$),
+ "*goes hide in a corner %%S.*", 1);
+ set(getvariableofnpc(.shut_up, .npc$), getarraysize(getvariableofnpc(.shut_up$, .npc$)));
+
+ setarray(getvariableofnpc(.climb$[1], .npc$),
+ "*sways violently.*", 1,
+ "*bends all the way to the ground.*", 1,
+ "*creaks and bends.*", 1,
+ "*welcomes those who come to play %%I.*", 1,
+ "*beams with pride.*", 1);
+ set(getvariableofnpc(.climb, .npc$), getarraysize(getvariableofnpc(.climb$, .npc$)));
+
+ return;
+}
diff --git a/npc/functions/crafting.txt b/npc/functions/crafting.txt
new file mode 100644
index 00000000..fa5fa84e
--- /dev/null
+++ b/npc/functions/crafting.txt
@@ -0,0 +1,119 @@
+// Moubootaur Legends Script
+// Author:
+// Jesusalva
+// Gumi
+// Description:
+// Smith System (Unified)
+// Notes:
+// Modified for The Mana World: rEvolt
+//
+// This one is more crazy. Cannot be equipping target craft.
+// After successful craft, we use CraftDB return code to equip() the
+// new item and apply a random option bonus based on crafter skills
+// eg. setequipoption(EQI_HAND_R, 1, VAR_STRAMOUNT, 5)
+
+// Usage: SmithSystem ({scope=CRAFT_SMITHERY, checks=True})
+// Returns true on success, false on failure
+function script SmithSystem {
+ .@scope=getarg(0, CRAFT_SMITHERY);
+ mesc l("WARNING: Strange bugs may happen if you attempt to craft an item you already have on inventory!"), 1;
+ setskin "craft4";
+ .@var$ = requestcraft(4);
+ .@craft = initcraft(.@var$);
+ .@entry = findcraftentry(.@craft, .@scope);
+ if (debug || $@GM_OVERRIDE) mes "found craft entry: " + .@entry;
+ if (debug || $@GM_OVERRIDE) mes "knowledge value: " + .knowledge[.@entry];
+ if (.@entry < 0) {
+ .success=false;
+ } else {
+ if (!getarg(1, true) || RECIPES[.@entry]) {
+ // Player craft item and setup base variables
+ usecraft .@craft;
+ .@it=getcraftcode(.@entry);
+ .@lv=getiteminfo(.@it, ITEMINFO_ELV);
+ .@skill=getskilllv(EVOL_CRAFTING);
+
+ // Update your CRAFTING_SCORE
+ CRAFTING_SCORE+=.@lv;
+
+ // Obtain the item. No bounds or restrictions applied.
+ getitem(.@it, 1);
+
+ // This is where we add options - this is oversimplified
+ // delinventorylist() is needed, because we'll rely on rfind()
+ delinventorylist();
+ getinventorylist();
+ .@index=array_rfind(@inventorylist_id, .@it);
+
+ // Prepare the options
+ .@isweapon=(getiteminfo(.@it, ITEMINFO_TYPE) == IT_WEAPON);
+ .@bonus=(.@isweapon ? VAR_ATTPOWER : VAR_ITEMDEFPOWER);
+ .@magic=(.@isweapon ? VAR_ATTMPOWER : VAR_MDEFPOWER);
+ .@buffs=(.@isweapon ? VAR_HITSUCCESSVALUE : VAR_AVOIDSUCCESSVALUE);
+ .@heals=(.@isweapon ? VAR_MAXSPAMOUNT : VAR_MAXHPAMOUNT);
+
+ // Now we need to randomly decide what will be .@opt1 and .@opt2
+ // Would be better to not rely on rand here, though.
+ .@opt1=any(.@bonus, .@magic);
+ .@opt2=any(.@buffs, .@heals);
+
+ // Apply the bonuses. They're capped by equip level and based on:
+ // Equip level, crafting experience and crafting skill
+ .@val=min(.@lv, (.@skill*CRAFTING_SCORE)/100+.@skill);
+
+ // MDEF rule range is 99 while DEF rule range is 399
+ // This is a really hackish way, for the record
+ if (.@opt1 == VAR_MDEFPOWER)
+ .@val=.@val/4;
+
+ // First option will always succeed
+ .@val1=rand2(.@val);
+ setitemoptionbyindex(.@index, 0, .@opt1, .@val1);
+
+ // Lucky roll (5% per skill level, capped at 50%)
+ // The lucky roll will add the extra attributes
+ if (rand2(20) < .@skill) {
+ .@val2=rand2(.@val);
+ setitemoptionbyindex(.@index, 1, .@opt2, .@val2);
+ }
+
+ // Get experience for the craft
+ // I'm using the same EXP formula from Moubootaur Legends
+ // Which is based on the item sell price
+ .@xp=getiteminfo(.@it, ITEMINFO_SELLPRICE);
+ quest_xp(.@lv+10, .@xp+BaseLevel);
+ quest_jxp(.@lv+10, (.@xp/3)+BaseLevel+JobLevel);
+ .success=true;
+ } else {
+ .success=false;
+ }
+ }
+ deletecraft .@craft;
+ setskin "";
+ return .success;
+}
+
+- script @craft FAKE_NPC,{
+ public function DoTailoring {
+ SmithSystem(CRAFT_TAILORING);
+ end;
+ }
+
+ public function DoSmithery {
+ SmithSystem(CRAFT_SMITHERY);
+ end;
+ }
+
+ public function OnInit {
+ if (debug < 1) {
+ end;
+ }
+
+ bindatcmd("@tailoring", sprintf("%s::%s", .name$, "DoTailoring"));
+ bindatcmd("@tailor", sprintf("%s::%s", .name$, "DoTailoring"));
+ bindatcmd("@smithery", sprintf("%s::%s", .name$, "DoSmithery"));
+ bindatcmd("@smith", sprintf("%s::%s", .name$, "DoSmithery"));
+ bindatcmd("@blacksmithery", sprintf("%s::%s", .name$, "DoSmithery"));
+ end;
+ }
+}
diff --git a/npc/functions/daily.txt b/npc/functions/daily.txt
new file mode 100644
index 00000000..6de9ef27
--- /dev/null
+++ b/npc/functions/daily.txt
@@ -0,0 +1,154 @@
+// The Mana World scripts.
+// Author:
+// TMW Team
+// Jesusalva
+// Description:
+// Daily Quest framework
+// Variables returned:
+// .@dq_return - Code of what happend
+// DAILY_LOWLEVEL = Low level
+// DAILY_IGNORED = Ignored NPC
+// DAILY_NOPTS = Not enough points
+// DAILY_NOITEMS = Not enough items
+// DAILY_OK = Success
+
+// Variables to set:
+// .@dq_level - Minimal level needed to use the quest
+// .@dq_cost - The number of points this quest uses
+// .@dq_count - The number of given item needed
+// .@dq_name - Item Aegis
+// .@dq_money - The money reward for doing the quest
+// .@dq_exp - Experince gained by doing the quest
+
+// Optional:
+// .@dq_handle_return - When set to anything other then 0 the function will not print exiting text
+
+// Variables used inside:
+// DailyQuestPoints - The number of points the player currently has
+// DailyQuestTime - Time since DailyQuestPoints was lasted renewed
+// DailyQuestBonus - Additional points added in addition to player BaseLevel
+
+// (DailyQuestBonus makes a good reward from non-daily quests)
+
+function script DailyQuestPointsFunc {
+ .@dq_earliest = gettimetick(2) - 86400;
+ if (DailyQuestTime < .@dq_earliest)
+ DailyQuestTime = .@dq_earliest;
+
+ // how many whole daily quest points the player has earned
+ // we increment DailyQuestTime by the number of seconds in that many increments
+ .@dq_increments = (gettimetick(2) - DailyQuestTime)*BaseLevel / 86400;
+ DailyQuestTime = DailyQuestTime + .@dq_increments*86400/BaseLevel;
+
+ // player can't regenerate any quest points, but might have a bonus
+ if (DailyQuestPoints < BaseLevel) {
+ // normal recharging case - increment, but don't let it recharge more than a day's worth
+ DailyQuestPoints = DailyQuestPoints + .@dq_increments;
+ if (DailyQuestPoints > BaseLevel)
+ DailyQuestPoints = BaseLevel;
+ }
+
+ // fallthrough to bonus, which *is* allowed to push DailyQuestPoints above BaseLevel
+ DailyQuestPoints = DailyQuestPoints + DailyQuestBonus;
+ DailyQuestBonus = 0;
+ return;
+
+}
+
+// DailyQuest(lvl, cost, count, item, {exp, money})
+function script DailyQuest {
+ // Sanitize
+ DailyQuestPointsFunc();
+
+ // Load variables
+ .@dq_level=getarg(0);
+ .@dq_cost=getarg(1);
+ .@dq_count=getarg(2);
+ .@dq_name=getarg(3);
+ // Money defaults to 200% sell value, experience to 300% sell value
+ .@dq_exp=getarg(4, getiteminfo(.@dq_name, ITEMINFO_SELLPRICE)*.@dq_count*3);
+ .@dq_money=getarg(5, getiteminfo(.@dq_name, ITEMINFO_SELLPRICE)*.@dq_count*2);
+
+ // Insufficient level
+ if (BaseLevel < .@dq_level) {
+ mesq l("Hey, you should go kill some things to get stronger first.");
+ return DAILY_LOWLEVEL;
+ }
+
+ // Insufficient points
+ if (DailyQuestPoints < .@dq_cost) {
+ mesq l("You look exhausted, maybe you should rest a bit.");
+ return DAILY_NOPTS;
+ }
+
+ mesq l("If you bring me %d %s, I will give you a reward.", .@dq_count, getitemlink(.@dq_name));
+ select
+ l("I have what you want."),
+ l("Take all you need."),
+ l("Ok, I'll get to work."),
+ l("Nah, I'm not going to help you.");
+ mes "";
+
+ if (@menu >= 3)
+ return DAILY_IGNORED;
+
+ if (countitem(.@dq_name) < .@dq_count) {
+ mesq l("I said %d %s; you should learn to count.", .@dq_count, getitemlink(.@dq_name));
+ return DAILY_NOITEMS;
+ }
+
+ // Default multiplier
+ .@multiplier = 1;
+
+ if (@menu == 1) {
+ delitem .@dq_name, .@dq_count;
+
+ Zeny = Zeny + .@dq_money;
+ getexp .@dq_exp, 0;
+
+ DailyQuestPoints = DailyQuestPoints - .@dq_cost;
+
+ }
+ else
+ {
+
+ .@item_multiple = (countitem(.@dq_name) / .@dq_count);
+ .@dp_multiple = (DailyQuestPoints / .@dq_cost);
+
+ if (.@dp_multiple > .@item_multiple)
+ .@multiplier = .@item_multiple;
+ if (.@item_multiple >= .@dp_multiple)
+ .@multiplier = .@dp_multiple;
+
+ DailyQuestPoints = DailyQuestPoints - (.@dq_cost * .@multiplier);
+
+ delitem .@dq_name, (.@dq_count * .@multiplier);
+
+ Zeny = Zeny + (.@dq_money * .@multiplier);
+ getexp (.@dq_exp * .@multiplier), 0;
+
+ if (.@dq_handle_return)
+ goto L_Exit_Good;
+ }
+
+ mesq l("Thank you!");
+
+ if (DailyQuestPoints < .@dq_cost)
+ mesq l("You look exhausted, maybe you should rest a bit.");
+ else if (DailyQuestPoints > BaseLevel)
+ mesq l("Woah, you're bursting with power.");
+ else if (DailyQuestPoints > (BaseLevel*9)/10)
+ mesq l("You're in a very good shape.");
+ else if (DailyQuestPoints > (BaseLevel*7)/10)
+ mesq l("You don't seem very exhausted by my tasks.");
+ else if (DailyQuestPoints > (BaseLevel*5)/10)
+ mesq l("Aren't you getting weary yet?");
+ else
+ mesq l("You look a little tired.");
+
+ mes "";
+ mesc l("+%d money", (.@dq_money * .@multiplier));
+ mesc l("+%d experience points", (.@dq_exp * .@multiplier));
+ return DAILY_OK;
+}
+
diff --git a/npc/functions/doors.txt b/npc/functions/doors.txt
new file mode 100644
index 00000000..9382a015
--- /dev/null
+++ b/npc/functions/doors.txt
@@ -0,0 +1,65 @@
+// Evol functions.
+// Author:
+// 4144
+// Description:
+// Doors utility functions
+// Variables:
+// none
+
+function script doorTouch {
+ getmapxy(.@pc_map$, .@pc_x, .@pc_y, UNITTYPE_PC); // get char location
+ if (.@pc_y < .y)
+ end;
+
+ if (getareausers() <= 1)
+ {
+ .dir = 2;
+ stopnpctimer;
+ initnpctimer;
+ }
+ close;
+}
+
+function script doorUnTouch {
+ if (.dir != 2 && .dir != 6)
+ end;
+
+ if (getareausers(.map$) == 0)
+ {
+ .dir = 4;
+ initnpctimer;
+ startnpctimer;
+ }
+ close;
+}
+
+function script doorTimer {
+ stopnpctimer;
+ if (.dir == 2) .dir = 6;
+ if (.dir == 4) .dir = 8;
+ end;
+}
+
+function script doorInit {
+ .distance = 5;
+ .alwaysVisible = true;
+ end;
+}
+
+function script open_door {
+ .@door$ = getarg(0);
+ setnpcdir.@door$, 2;
+ sleep 300;
+ setnpcdir .@door$, 6;
+ sleep 300;
+ return 0;
+}
+
+function script close_door {
+ .@door$ = getarg(0);
+ setnpcdir .@door$, 4;
+ sleep 300;
+ setnpcdir .@door$, 8;
+ sleep 300;
+ return 0;
+}
diff --git a/npc/functions/event-listeners.txt b/npc/functions/event-listeners.txt
new file mode 100644
index 00000000..111b2737
--- /dev/null
+++ b/npc/functions/event-listeners.txt
@@ -0,0 +1,169 @@
+// Event listeners work similar to the JavaScript event dispatching system,
+// except that the event object is a hash table.
+//
+// Javascript reference:
+// https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
+//
+// Example usage:
+/*
+// Create a handler function:
+public function myHandler {
+ // ... do something with getarg(0)
+}
+
+// Create a new event:
+$@event = htnew();
+
+// Listen for the event:
+addEventListener($@event, "myHandler");
+
+// Dispatch the event:
+dispatchEvent($@event, "misc data");
+*/
+
+
+/**
+ * getEventHt(<hash table expression>) => ht id
+ *
+ * Parses a hash table "event" expression and creates one when necessary.
+ * The following are all valid:
+ *
+ * getEventHt(.@ht); // variable
+ * getEventHt(72); // arbitrary integer (global namespace)
+ * getEventHt("some event"); // arbitrary string (global namespace)
+ *
+ * NOTE: This is only called internally; you don't have to use this function
+ *
+ * @param 0 - a variable / string / integer
+ * @return the hash table id
+ */
+function script getEventHt {
+ .@ht = ((getdatatype(getarg(0)) & (DATATYPE_VAR | DATATYPE_INT)) != 0) ? getarg(0) : 0;
+
+ if (htexists(.@ht)) {
+ // this is already a valid hash table
+ return getarg(0);
+ } else if ((getdatatype(getarg(0)) & DATATYPE_VAR) != 0) {
+ // the hash table doesn't exist yet: create one and store it in the
+ // provided variable
+
+ if ((getdatatype(getarg(0)) & DATATYPE_STR) != 0) {
+ consolemes(CONSOLEMES_ERROR, "getEventHt: variable must be an integer variable (cannot use %s)", data_to_string(getarg(0)));
+ end;
+ }
+
+ if (getarg(0) > 0) {
+ consolemes(CONSOLEMES_WARNING, "getEventHt: variable is already assigned (overwriting %s)", data_to_string(getarg(0)));
+ }
+
+ return set(getarg(0), htnew());
+ } else {
+ // global event listener namespace
+ if ($@GLOBAL_EVTL_HT < 1) {
+ $@GLOBAL_EVTL_HT = htnew();
+
+ // the global scope is new: create a new one
+ .@ht = htnew();
+ htput($@GLOBAL_EVTL_HT, data_to_string(getarg(0)), "" + .@ht);
+ return .@ht;
+ } else if ((.@ht$ = htget($@GLOBAL_EVTL_HT, data_to_string(getarg(0)), "")) != "") {
+ // found in the global scope
+ return atoi(.@ht$);
+ } else {
+ // not found in the global scope: create new
+ .@ht = htnew();
+ htput($@GLOBAL_EVTL_HT, data_to_string(getarg(0)), "" + .@ht);
+ return .@ht;
+ }
+ }
+}
+
+/**
+ * addEventListener(<ht: event>, "<handler: public local function>") => void
+ *
+ * Register a public local function in the current NPC as an event handler for
+ * the given hash table. Can also register for another NPC using the syntax
+ * `npcName::function`
+ *
+ * NOTE: only one handler may be assigned per NPC per Event
+ *
+ * @param 0 - the event to listen to (string, variable, or hash table)
+ * @param 1 - the event handler (must be a public local function)
+ */
+function script addEventListener {
+ .@ht = getEventHt(getarg(0));
+ .@pos = strpos(getarg(1), "::");
+
+ if (.@pos > -1) {
+ .@id = getnpcid(substr(getarg(1), 0, .@pos - 1));
+ .@function$ = substr(getarg(1), .@pos + 2, getstrlen(getarg(1)) - 1);
+ } else {
+ .@id = getnpcid();
+ .@function$ = getarg(1);
+ }
+
+ if (.@id == 0) {
+ consolemes(CONSOLEMES_WARNING, "addEventListener: the target NPC doesn't exist");
+ return;
+ }
+
+ // TODO: check that the target function exists
+ return htput(.@ht, "" + .@id, .@function$);
+}
+
+/**
+ * dispatchEvent(<ht: event>{, ...<arg>}) => bool
+ *
+ * Calls every event handler for the given hash table and passes the given
+ * arguments (if any)
+ *
+ * @param 0 - the event to dispatch (string, variable, or hash table)
+ * @return true when handlers were called, else false
+ */
+function script dispatchEvent {
+ .@ht = getEventHt(getarg(0));
+
+ if (htsize(.@ht) < 1) {
+ // no handler to call
+ return false;
+ }
+
+ .@it = htiterator(.@ht);
+
+ freeloop(true);
+ for (.@npc$ = htinextkey(.@it); hticheck(.@it); .@npc$ = htinextkey(.@it)) {
+ if (.@npc$ == "") {
+ continue;
+ }
+
+ .@func$ = htget(.@ht, .@npc$, "");
+
+ // this is ugly but we don't have rest parameters (...args) to apply args to function calls
+ switch (getargcount()) {
+ case 1:
+ callfunctionofnpc(atoi(.@npc$), .@func$);
+ break;
+ case 2:
+ callfunctionofnpc(atoi(.@npc$), .@func$, getarg(1));
+ break;
+ case 3:
+ callfunctionofnpc(atoi(.@npc$), .@func$, getarg(1), getarg(2));
+ break;
+ case 4:
+ callfunctionofnpc(atoi(.@npc$), .@func$, getarg(1), getarg(2), getarg(3));
+ break;
+ case 5:
+ callfunctionofnpc(atoi(.@npc$), .@func$, getarg(1), getarg(2), getarg(3), getarg(4));
+ break;
+ default:
+ consolemes(CONSOLEMES_WARNING, "dispatchEvent: truncating to 5 arguments (%d given)", getargcount() - 1);
+ case 6:
+ callfunctionofnpc(atoi(.@npc$), .@func$, getarg(1), getarg(2), getarg(3), getarg(4), getarg(5));
+ break;
+ }
+ }
+ freeloop(false);
+
+ htidelete(.@it);
+ return true;
+}
diff --git a/npc/functions/faction.txt b/npc/functions/faction.txt
new file mode 100644
index 00000000..497c469a
--- /dev/null
+++ b/npc/functions/faction.txt
@@ -0,0 +1,104 @@
+// The Mana World: rEvolt functions.
+// Authors:
+// Jesusalva
+// Description:
+// Faction utils
+// Factions:
+// THIEF / MAGE / LEGION / BROTHERHOOD
+// Variables:
+// FACTION_REP
+// Your reputation with the faction (ally, friendly, cordial, enemy, ...)
+// FACTION_EXP
+// Your personal experience (=skill with the faction dealings)
+// FACTION_RANK
+// Your "level" in the faction, a mix of both above.
+
+
+// Returns, based on a 1-5 range, the title for ranking systems (system guilds)
+// legionrank() / brotherrank() / thiefrank() / magerank()
+function script legionrank {
+ switch (LEGION_RANK) {
+ case 5: return l("Admiral");
+ case 4: return l("Constable");
+ case 3: return l("Lieutenant");
+ case 2: return l("Sergeant");
+ case 1: return l("Private");
+ case 0: return l("Citizen");
+ default: return l("Error");
+ }
+}
+function script brotherrank {
+ switch (BROTHERHOOD_RANK) {
+ case 5: return l("Administrator");
+ case 4: return l("Senior Developer");
+ case 3: return l("Game Master");
+ case 2: return l("Developer");
+ case 1: return l("Contributor");
+ case 0: return l("Citizen");
+ default: return l("Error");
+ }
+}
+function script thiefrank {
+ switch (THIEF_RANK) {
+ case 5: return l("Bandit Lord");
+ case 4: return l("Assassin");
+ case 3: return l("Rogue");
+ case 2: return l("Bandit");
+ case 1: return l("Thief");
+ case 0: return l("Citizen");
+ default: return l("Error");
+ }
+}
+function script magerank {
+ switch (MAGE_RANK) {
+ case 5: return l("Elder Mage");
+ case 4: return l("Great Mage");
+ case 3: return l("Arch Mage");
+ case 2: return l("Mage");
+ case 1: return l("Initiate");
+ case 0: return l("Citizen");
+ default: return l("Error");
+ }
+}
+
+// faction_addrep( faction, amount )
+// Returns a dialog which can be used with mesc() or dispbottom()
+function script faction_addrep {
+ .@fac$=strtoupper(getarg(0));
+ .@old=getd(.@fac$+"_REP");
+ setd(.@fac$+"_REP", .@old+getarg(1));
+ if (getarg(1) > 0)
+ return l("Reputation with %s Faction UP (+%d)!", getarg(0), getarg(1));
+ else
+ return l("Reputation with %s Faction DOWN (%d)!", getarg(0), getarg(1));
+
+ return;
+}
+
+// Returns standing with faction (THIEF/MAGE/LEGION/BROTHERHOOD)
+// An integer from 3 (ally) to -3 (enemy). Standings based on Hands of War;
+// faction_standing( faction{, integer=True} )
+function script faction_standing {
+ .@fac$=strtoupper(getarg(0));
+ .@ret=getarg(1, true);
+ .@rep=getd(.@fac$+"_REP");
+ if (.@rep > 1000) {
+ return (.@ret ? 3 : "Ally"); // 1001 ~ inf.
+ } else if (.@rep > 500) {
+ return (.@ret ? 2 : "Friendly"); // 501 ~ 1000
+ } else if (.@rep > 100) {
+ return (.@ret ? 1 : "Cordial"); // 101 ~ 500
+ } else if (.@rep >= -100) {
+ return (.@ret ? 0 : "Neutral"); // -100 ~ +100
+ } else if (.@rep > -500) {
+ return (.@ret ? -1 : "Unfriendly"); // -101 ~ -500
+ } else if (.@rep > -1000) {
+ return (.@ret ? -2 : "Enemy"); // -501 ~ -1000
+ } else {
+ return (.@ret ? -3 : "Nemesis"); // -1001 ~ inf
+ }
+
+}
+// TODO: faction_checklvup()
+
+
diff --git a/npc/functions/fishing.txt b/npc/functions/fishing.txt
new file mode 100644
index 00000000..4dcb4882
--- /dev/null
+++ b/npc/functions/fishing.txt
@@ -0,0 +1,401 @@
+// Evol functions.
+// Authors:
+// gumi
+// omatt
+// Travolta
+// Reid
+// Jesusalva
+// Description:
+// Fishing functions.
+// Variable
+// .dir
+// DOWN Never try or pulled too late
+// UP Bait dropped
+// LEFT Fish bite bait
+//
+// player log on .dir is DOWN, start by choose bait menu
+// player chooses bait, script addtimer in npc .dir is UP
+// if player pulls before signal npc, bait is lost, set .bait to DOWN goto choose bait
+// if player pulls after pull delay max, bait is lost, set .bait to DOWN goto choose bait
+// npc signal .dir is LEFT
+// player pulls between npc signal and pulls delay max, got the fish, set .dir to DOWN goto choose bait
+
+function script fishing_cleanup {
+ .@npc$ = getarg(0, "");
+ if (.@npc$ == "") end;
+
+ set getvariableofnpc(.char_id, .@npc$), 0; // clean acc id
+ set getvariableofnpc(.account_id, .@npc$), 0; // clean char id
+ set getvariableofnpc(.last_used, .@npc$), gettimetick(2); // set last used time
+ setnpcdir .@npc$, DOWN; // reset direction
+ return;
+}
+
+- script global fishing handler 32767,{
+ end;
+
+OnBite:
+ if (getnpcdir(@fishing_spot$) != UP)
+ end;
+
+ setnpcdir @fishing_spot$, LEFT;
+ @fishing_tick = gettimetick(0);
+ specialeffect(getvariableofnpc(.bite_fx, @fishing_spot$), SELF, playerattached());
+ end;
+
+OnCleanUp:
+ dispbottom l("You waited too long and lost the bait...");
+ specialeffect(getvariableofnpc(.failure_fx, @fishing_spot$), SELF, playerattached()); // event fail
+ fishing_cleanup(@fishing_spot$);
+ @fishing_spot$ = ""; // unbind fishing npc
+ end;
+}
+
+function script fishing {
+
+///////////////////////////////////////////
+// Var initialization
+
+ .@npc$ = strnpcinfo(0); // the full name of the fishing spot
+
+ .@account_id = getvariableofnpc(.account_id, .@npc$); // the account id of the player using the fishing spot
+ .@char_id = getvariableofnpc(.char_id, .@npc$); // the char id of the player using the fishing spot
+ .@dir = getnpcdir(.@npc$); // direction of the fishing spot
+ .@last_used = getvariableofnpc(.last_used, .@npc$); // when this fishing spot was last used
+ .@baits = getvariableofnpc(.baits, .@npc$); // bait count
+
+ .@rod = getvariableofnpc(.fishing_rod, .@npc$); // the fishing rod required for this spot
+ .@rod = (.@rod ? .@rod : FishingRod);
+
+ .@regen_time = getvariableofnpc(.cooldown, .@npc$); // cooldown for the fishing spot
+ .@regen_time = (.@regen_time ? .@regen_time : 20);
+
+ .@success_fx = getvariableofnpc(.success_fx, .@npc$); // effect to show on success
+ .@success_fx = (.@success_fx ? .@success_fx : 27);
+
+ .@failure_fx = getvariableofnpc(.failure_fx, .@npc$); // effect to show on failure
+ if (.@failure_fx < 1)
+ {
+ .@failure_fx = 28;
+ set getvariableofnpc(.failure_fx, .@npc$), .@failure_fx; // needed by global handler
+ }
+
+ .@initial_fx = getvariableofnpc(.initial_fx, .@npc$); // effect to show when throwing the bait
+ .@initial_fx = (.@initial_fx ? .@initial_fx : 29);
+
+ .@bite_fx = getvariableofnpc(.bite_fx, .@npc$); // effect to show when something bites
+ if (.@bite_fx < 1)
+ {
+ .@bite_fx = 30;
+ set getvariableofnpc(.bite_fx, .@npc$), .@bite_fx; // needed by global handler
+ }
+
+ .@wait_time_min = getvariableofnpc(.wait_time_min, .@npc$); // min amount of time to wait for the line to sink
+ .@wait_time_min = (.@wait_time_min ? .@wait_time_min : 4000);
+
+ .@wait_time_max = getvariableofnpc(.wait_time_max, .@npc$); // max amount of time to wait for the line to sink
+ .@wait_time_max = (.@wait_time_max ? .@wait_time_max : 18000);
+
+ .@catch_time = getvariableofnpc(.catch_time, .@npc$); // the player must catch the fish within X ms after the line sinks
+ .@catch_time = (.@catch_time ? .@catch_time : 5000);
+
+ .@pull_rand_max = getvariableofnpc(.pull_rand_max, .@npc$);
+ .@pull_rand_max = (.@pull_rand_max ? .@pull_rand_max : 800);
+
+
+ if (getvariableofnpc(.bait_ids[1], .@npc$) < 1)
+ {
+ // default baits (bait, chance booster)
+ // TODO: we should have some fish prefer certain baits while other
+ // prefer other bait. currently all fish prefer the same baits
+ setarray getvariableofnpc(.bait_ids[1], .@npc$),
+ SmallTentacles, 0,
+ Bread, 0,
+ Aquada, 1,
+ UrchinMeat, 0,
+ TortugaTongue, 2,
+ Tentacles, 0;
+ }
+
+ if (getvariableofnpc(.fish_ids[1], .@npc$) < 1)
+ {
+ // default fish: <array: 0, {[fish, probability]..}>
+ setarray getvariableofnpc(.fish_ids[1], .@npc$),
+ CommonCarp, 25,
+ GrassCarp, 1;
+ }
+
+ if (.@baits < 1)
+ {
+ // only count it once
+ .@baits = getarraysize(getvariableofnpc(.bait_ids[0], .@npc$));
+ set getvariableofnpc(.baits, .@npc$), .@baits;
+ }
+
+
+///////////////////////////////////////////
+// Logic below
+
+ if (countitem(.@rod) < 1)
+ {
+ dispbottom l("You don't have any @@.", getitemlink(.@rod));
+ return -1;
+ }
+
+ if (.@account_id > 0 && !isloggedin(.@account_id, .@char_id))
+ {
+ fishing_cleanup .@npc$; // reset
+ .@dir = DOWN;
+ }
+
+ if (.@char_id != getcharid(CHAR_ID_CHAR) && .@dir != DOWN)
+ {
+ dispbottom l("This fishing spot is already being used!");
+ return -2;
+ }
+
+
+ // pull too soon
+ if (.@dir == UP)
+ {
+ deltimer "global fishing handler::OnCleanUp"; // cancel auto cleanup
+ deltimer "global fishing handler::OnBite";
+ specialeffect(.@failure_fx, SELF, playerattached()); // event fail
+ fishing_cleanup .@npc$; // do it manually instead
+ dispbottom l("You pulled too soon and lost the bait.");
+ return -3;
+ }
+
+ // pull maybe on time
+ else if (.@dir == LEFT)
+ {
+ deltimer "global fishing handler::OnCleanUp"; // cancel auto cleanup
+ fishing_cleanup .@npc$; // do it manually instead
+
+ getmapxy .@mapbis$, .@xbis, .@ybis, UNITTYPE_PC; // get current char location
+
+ // Leave spot, lost the bait
+ if (.@mapbis$ != @fishing_loc$[0] || .@xbis != @fishing_loc[0] || .@ybis != @fishing_loc[1] || @fishing_spot$ != .@npc$)
+ {
+ dispbottom l("You left your fishing spot!");
+ return -4;
+ }
+
+ .@fish_id = relative_array_random(getvariableofnpc(.fish_ids[0], .@npc$));
+
+ // RNG to obtain a fish
+ if (rand(gettimetick(0) - @fishing_tick) <= .@pull_rand_max + (100 * @FISHING_BOOSTER[getnpcid()]))
+ {
+ specialeffect(.@success_fx, SELF, playerattached()); // event success
+
+ if(!checkweight(.@fish_id, 1))
+ {
+ dispbottom l("You caught a @@ but had no room in your inventory to carry it.", getitemlink(.@fish_id));
+ makeitem .@fish_id, 1, .@mapbis$, .@xbis, .@ybis; // drop on the ground
+ return 0;
+ }
+
+ //dispbottom l("You caught a @@!", getitemlink(.@fish_id)); <= already shows "you picked up [...]"
+ getitem .@fish_id, 1;
+ }
+ else
+ {
+ dispbottom l("You pulled too late and lost the bait...");
+ specialeffect(.@failure_fx, SELF, playerattached()); // event fail
+ .@fish_id = 0;
+ }
+
+ return .@fish_id;
+ }
+
+
+
+ if (gettimetick(2) - .@last_used < .@regen_time)
+ {
+ dispbottom l("This fishing spot has just been used, give it a rest.");
+ return -5;
+ }
+
+
+ // begin fishing
+ narrator S_LAST_NEXT,
+ l("You see some fish reflecting the sun on the surface of the water."),
+ l("What will be the bait for the fish?");
+
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+
+ .@bait = requestitem();
+ .@bait_c = false;
+
+ if (.@bait < 1)
+ {
+ narrator S_FIRST_BLANK_LINE,
+ l("You take your fishing rod and leave.");
+
+ return -6;
+ }
+
+ if (countitem(.@bait) < 1)
+ {
+ return -6;
+ }
+
+ for (.@i = 1; .@i < .@baits; .@i += 2)
+ {
+ if (getvariableofnpc(.bait_ids[.@i], .@npc$) == .@bait)
+ {
+ .@bait_c = true;
+ @FISHING_BOOSTER[getnpcid()] = getvariableofnpc(.bait_ids[.@i + 1], .@npc$);
+ break;
+ }
+ }
+
+ if (.@bait_c != true)
+ {
+ narrator S_FIRST_BLANK_LINE,
+ l("This item cannot be used as bait here.");
+
+ return -6;
+ }
+
+ if (getvariableofnpc(.char_id, .@npc$) > 0)
+ {
+ narrator S_FIRST_BLANK_LINE,
+ l("Somebody took your place on this spot!"),
+ l("You take your fishing rod and leave.");
+ return -8;
+ }
+
+ @fishing_spot$ = .@npc$; // bind player to fishing spot
+ set getvariableofnpc(.account_id, .@npc$), getcharid(CHAR_ID_ACCOUNT); // record account id
+ set getvariableofnpc(.char_id, .@npc$), getcharid(CHAR_ID_CHAR); // record char id
+ set getvariableofnpc(.last_used, .@npc$), gettimetick(2);
+ getmapxy(@fishing_loc$[0], @fishing_loc[0], @fishing_loc[1], 0); // record char pos
+ delitem .@bait, 1;
+
+ // The player uses this spot, his bait is ready, he just has to wait for the signal.
+ closeclientdialog;
+
+ specialeffect(.@initial_fx, SELF); // throw the bait
+ sleep2 800; // wait 0.8s for synchronize the sound of "plop" in water with the npc dir UP.
+ setnpcdir .@npc$, UP;
+
+ dispbottom l("Wait for the bait to sink underwater.");
+
+ .@delay = rand(.@wait_time_min, .@wait_time_max);
+
+ addtimer .@delay, "global fishing handler::OnBite"; // bite logic
+ addtimer (.@delay + .@catch_time), "global fishing handler::OnCleanUp"; // auto clean up
+
+ return 0;
+}
+
+
+////////////////////
+// Fishing Templates
+
+// #fish_basic - has only carps (freshwater)
+- script #fish_basic NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ GrassCarp, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5000; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 4000; // min amount of time to wait for the line to sink
+ .wait_time_max = 18000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+// #fish_seawater - has only tuna
+- script #fish_seawater NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ Tuna, 15,
+ Salmon, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 4000; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 8000; // min amount of time to wait for the line to sink
+ .wait_time_max = 18000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+
+// #fish_river - A balanced fishing spot for Woodlands (Trout)
+- script #fish_river NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ Trout, 20,
+ GrassCarp, 5,
+ Salmon, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5500; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 5000; // min amount of time to wait for the line to sink
+ .wait_time_max = 16000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+
+
+// #fish_river2 - A balanced fishing spot for Candor (Salmon)
+- script #fish_river2 NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ Salmon, 20,
+ GrassCarp, 5,
+ Trout, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5500; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 5000; // min amount of time to wait for the line to sink
+ .wait_time_max = 16000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+
+
+// #fish_frozen - A fishing spot with cold waters (for Nivalis)
+- script #fish_frozen NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ Codfish, 20,
+ GrassCarp, 5,
+ Salmon, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5500; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 5000; // min amount of time to wait for the line to sink
+ .wait_time_max = 16000; // max amount of time to wait for the line to sink
+ end;
+}
+
diff --git a/npc/functions/game-rules.txt b/npc/functions/game-rules.txt
new file mode 100644
index 00000000..053bec03
--- /dev/null
+++ b/npc/functions/game-rules.txt
@@ -0,0 +1,66 @@
+// Evol scripts.
+// Authors:
+// The Mana World Team
+// Co-Authors:
+// gumi
+// Qwerty Dragon
+// Reid
+// WildX
+// Description:
+// 7 main rules of The Mana World
+
+function script GameRules {
+ narrator getarg(0, 0),
+ l("1. ##BDo not AFK bot##b, this means you are not allowed to perform any AFK (away from keyboard) activity, apart from standing idle."),
+ l("2. ##BDo not use offensive/rude language##b in the chats or in your character(s) name(s)."),
+ l("3. ##BDo not spam/flood other players.##b This includes chat spam and spam by trade requests."),
+ l("4. ##BSpeak only English in public areas.##b You can speak whatever language you want through whispers or whenever everyone in the area can speak said language."),
+ l("5. ##BDo not beg others##b for money, items or favours of any kind. If you want to ask for something, do it politely and only once. Try not to annoy other players."),
+ l("6. ##BDo not multibox.##b You are not allowed to engage in combat while controlling more than one character at a time."),
+ l("7. ##BFollow the [@@https://policies.themanaworld.org/tsc|TMW Social Convention@@]##b (TSC)."),
+ l("In the event that the rules diverge from [@@https://policies.themanaworld.org/game-rules|policies.themanaworld.org@@], the later version takes priority.");
+ if (SERVER_USES_VAULT) {
+ mesc l("Note: You are NOT allowed to have multiple Vault accounts.");
+ if (getarg(0, 0) & S_LAST_NEXT)
+ next;
+ }
+ return;
+}
+
+
+- script @rules 32767,{
+ end;
+
+ function read_book {
+ narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("This book outlines the laws of every city and holding in Gasaron."),
+ l("The first page contains the universal rules that have been agreed upon throughout the land.");
+
+ GameRules S_NO_NPC_NAME | S_LAST_NEXT;
+
+ narrator S_NO_NPC_NAME,
+ l("The next page begins to list the complex trading laws of the City of Esperia"),
+ l("All this seems unimportant to you right now.");
+ close;
+ }
+
+OnCall:
+ GameRules;
+ close;
+
+OnUseBook:
+ if (openbook())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnShelfUse:
+ if (openbookshelf())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = "The Book of Laws";
+ bindatcmd "rules", "@rules::OnCall", 0, 2, 0;
+}
diff --git a/npc/functions/generic-text.txt b/npc/functions/generic-text.txt
new file mode 100644
index 00000000..ede6e954
--- /dev/null
+++ b/npc/functions/generic-text.txt
@@ -0,0 +1,120 @@
+// Evol functions.
+// Authors:
+// gumi
+// Description:
+// text register
+
+function script generic {
+ .@flags = getarg(0, 1);
+
+ .@villager = (1 << 0);
+ .@old = (1 << 1);
+ .@kid = (1 << 2);
+ .@sailor = (1 << 3);
+ .@busy = (1 << 4);
+ .@tired = (1 << 5);
+ .@angry = (1 << 6);
+ .@legion = (1 << 7);
+ .@crazy = (1 << 8);
+
+ if (.@flags == 0)
+ return l("I'm sorry, I can't talk right now.");
+
+ if (.@flags & .@villager)
+ {
+ setarray(.@array$[.@count],
+ l("It is a sunny day, don't you think?"),
+ l("I just want to live my life in peace."),
+ l("Isn't this place pretty? I love hanging out here!"));
+
+ .@count += 3;
+ }
+
+ if (.@flags & .@old)
+ {
+ setarray(.@array$[.@count],
+ l("Come closer dear, I can't hear you."),
+ l("Hmm... where did I put it again?"),
+ l("I miss the good old days."));
+
+ .@count += 3;
+ }
+
+ if (.@flags & .@kid)
+ {
+ setarray(.@array$[.@count],
+ l("Mommy doesn't want me to talk to strangers."));
+
+ .@count += 1;
+ }
+
+ if (.@flags & .@sailor)
+ {
+ setarray(.@array$[.@count],
+ l("So finally someone has came to visit me?"),
+ l("A-hoy matey!"));
+
+ .@count += 2;
+ }
+
+ if (.@flags & .@busy)
+ {
+ setarray(.@array$[.@count],
+ l("Can't talk right now."),
+ l("Can't you see I'm busy?"),
+ l("Come back later."),
+ l("I'm a little busy right now."));
+
+ .@count += 4;
+ }
+
+ if (.@flags & .@tired)
+ {
+ setarray(.@array$[.@count],
+ l("I had a long day, come back tomorrow."),
+ l("I need to rest."),
+ l("*snores*"));
+
+ .@count += 3;
+ }
+
+ if (.@flags & .@angry)
+ {
+ setarray(.@array$[.@count],
+ l("Go pester someone else."),
+ l("I don't feel like talking to you."),
+ l("Stop wasting my time."),
+ l("Go fly a kite"),
+ l("Not in the mood to chat."),
+ l("Give me some space."),
+ l("Can you please go away?"));
+
+ .@count += 7;
+ }
+
+ if (.@flags & .@legion)
+ {
+ setarray(.@array$[.@count],
+ l("My breath smells bad."),
+ l("Don't distract me, I have to stay alert."),
+ l("Can't talk right now, I'm on patrol duty."),
+ l("I can't stay here and talk all day. I have a job to do."),
+ l("Keep moving."),
+ l("So you think you're tough? A warrior must also be loyal and patient."),
+ l("Practice! There are no secrets to becoming a warrior."),
+ l("There is no honor in fighting a weak opponent."));
+
+ .@count += 8;
+ }
+
+ if (.@flags & .@crazy)
+ {
+ setarray(.@array$[.@count],
+ l("Do I look like a tree? I feel like one."),
+ l("What're you looking at?!"));
+
+ .@count += 2;
+ }
+
+ return .@array$[rand(.@count)];
+}
diff --git a/npc/functions/global_event_handler.txt b/npc/functions/global_event_handler.txt
new file mode 100644
index 00000000..3f10ae73
--- /dev/null
+++ b/npc/functions/global_event_handler.txt
@@ -0,0 +1,73 @@
+// The Mana World scripts.
+// Author:
+// The Mana World Team
+// Description:
+// Controls most, if not all, global events on this server.
+// Please only use callfunc("") here; This script is loaded
+// early on and direct function assignment will cause fails.
+// TODO: Move "new quest" notification here. (Or deprecate)
+
+// Helper function for scripted Monster Kills.
+function script fix_mobkill {
+ killedrid=getarg(0);
+ doevent "#GlobalHandler::OnNPCKillEvent";
+ return;
+}
+
+- script #GlobalHandler NPC_HIDDEN,{
+ end;
+
+
+OnPCLoginEvent:
+ callfunc("updateSpotlight");
+ callfunc("ReceiveMOTD");
+ callfunc("ReceiveScheduledBroadcast");
+ callfunc("FixBankVault");
+ callfunc("GrantSuperSkill");
+ callfunc("AFKLogin");
+ callfunc("TravelFix");
+ end;
+
+OnPCLogoutEvent:
+ callfunc("UnequipCookie");
+ callfunc("MundaneLogout");
+ callfunc("fishing_cleanup", @fishing_spot$);
+ callfunc("ATLFightEnd");
+ callfunc("RossyLogout");
+
+ // Variable cleanup
+ @fishing_spot$ = "";
+ end;
+
+OnPCDieEvent:
+ callfunc("ForcedUnmount");
+ callfunc("MundaneDeath");
+ callfunc("ATLFightEnd");
+ callfunc("RossyDeath");
+ end;
+
+OnPCBaseLvUpEvent:
+ //callfunc("newquestwarning");
+ callfunc("ReferralSendLvReward");
+ end;
+
+OnNPCKillEvent:
+ $MONSTERS_KILLED+=1;
+ MONSTERS_KILLED+=1;
+ callfunc("EnoraKills");
+ callfunc("refineupdate");
+ if ($MONSTERS_KILLED % 1000000 == 0)
+ callfunc("GetBeanieCopter");
+ end;
+
+OnPCKillEvent:
+ $PLAYERS_KILLED+=1;
+ PLAYERS_KILLED+=1;
+ end;
+
+OnSkillInvoke:
+ callfunc("SkillInvoked");
+ end;
+
+}
+
diff --git a/npc/functions/goodbye.txt b/npc/functions/goodbye.txt
new file mode 100644
index 00000000..6c8879c5
--- /dev/null
+++ b/npc/functions/goodbye.txt
@@ -0,0 +1,28 @@
+// Evol functions.
+// Authors:
+// Reid
+
+
+// goodbye
+// displays a canned message and quits
+
+function script goodbye {
+ setarray(.@byemsg$[0],
+ l("See you!"),
+ l("See you later!"),
+ l("See you soon!"),
+ l("Bye!"),
+ l("Farewell."),
+ l("Bye then!"),
+ l("Goodbye."),
+ l("Bye for now."),
+ l("Talk to you soon!"),
+ l("Talk to you later!"),
+ l("Have a good day!"),
+ l("Cheers!"),
+ l("Take care!"));
+
+ closeclientdialog();
+ npctalkonce(.@byemsg$[rand(getarraysize(.@byemsg$))]);
+ close;
+}
diff --git a/npc/functions/hammocks.txt b/npc/functions/hammocks.txt
new file mode 100644
index 00000000..8e1c2fec
--- /dev/null
+++ b/npc/functions/hammocks.txt
@@ -0,0 +1,50 @@
+// Evol functions.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Hammocks utility functions
+// Variables:
+// none
+
+function script hamTouchLeft {
+ if (getareausers() <= 1)
+ {
+ .dir = 0;
+ stopnpctimer;
+ initnpctimer;
+ }
+ close;
+}
+
+function script hamUnTouch {
+ if (getareausers() == 0)
+ {
+ .dir = 2;
+ initnpctimer;
+ startnpctimer;
+ }
+ close;
+}
+
+function script hamTimerLeft {
+ stopnpctimer;
+ if (.dir == 2) .dir = 0;
+ end;
+}
+
+function script hamTouchRight {
+ if (getareausers() <= 1)
+ {
+ .dir = 0;
+ stopnpctimer;
+ initnpctimer;
+ }
+ close;
+}
+
+function script hamTimerRight {
+ stopnpctimer;
+ if (.dir == 2) .dir = 0;
+ end;
+}
diff --git a/npc/functions/harbours.txt b/npc/functions/harbours.txt
new file mode 100644
index 00000000..63d58076
--- /dev/null
+++ b/npc/functions/harbours.txt
@@ -0,0 +1,39 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Harbour utility functions
+// Animation:
+// Length: 1680
+// Values:
+// 2 Hook moving down.
+// 4 Hook moving up.
+// 6 Hook down.
+// 8 Hook up.
+
+function script harbourClic {
+ if (.dir == 0)
+ {
+ .dir = 2;
+
+ initnpctimer;
+ startnpctimer;
+ close;
+ }
+
+ if (.dir == 6)
+ {
+ .dir = 4;
+
+ initnpctimer;
+ startnpctimer;
+ close;
+ }
+}
+
+function script harbourTimer {
+ stopnpctimer;
+ if (.dir == 2) .dir = 6;
+ if (.dir == 4) .dir = 0;
+ end;
+}
diff --git a/npc/functions/hello.txt b/npc/functions/hello.txt
new file mode 100644
index 00000000..9399b3b5
--- /dev/null
+++ b/npc/functions/hello.txt
@@ -0,0 +1,23 @@
+// Evol functions.
+// Author:
+// Reid
+// Description:
+// Tell a random greeting sentence.
+
+function script hello {
+
+ switch (rand(3))
+ {
+ case 0:
+ npctalkonce(l("Heya!"));
+ break;
+ case 1:
+ npctalkonce(l("Hi."));
+ break;
+ case 2:
+ npctalkonce(l("Nice day to you."));
+ break;
+ }
+
+ return;
+}
diff --git a/npc/functions/input.txt b/npc/functions/input.txt
new file mode 100644
index 00000000..cf0382d2
--- /dev/null
+++ b/npc/functions/input.txt
@@ -0,0 +1,66 @@
+// Evol functions.
+// Author:
+// 4144
+// Description:
+// Input utility functions
+// Variables:
+// none
+
+function script menuint {
+ deletearray .@vals;
+ .@menustr$ = "";
+ .@cnt = 0;
+
+ for (.@f = 0; .@f < getargcount(); .@f = .@f + 2)
+ {
+ if (getarg(.@f) != "")
+ {
+ .@menustr$ = .@menustr$ + getarg(.@f) + ":";
+ .@vals[.@cnt] = getarg(.@f + 1);
+ .@cnt ++;
+ }
+ }
+
+ .@vals[.@cnt] = -1;
+ @menu = 255;
+ @menuret = -1;
+ select(.@menustr$);
+ if (@menu == 255)
+ return -1;
+
+ @menu --;
+ if (@menu < 0 || @menu >= getarraysize(.@vals) - 1)
+ return -1;
+
+ @menuret = .@vals[@menu];
+ return @menuret;
+}
+
+function script menustr {
+ deletearray .@vals$;
+ .@menustr$ = "";
+ .@cnt = 0;
+
+ for (.@f = 0; .@f < getargcount(); .@f = .@f + 2)
+ {
+ if (getarg(.@f) != "")
+ {
+ .@menustr$ = .@menustr$ + getarg(.@f) + ":";
+ .@vals$[.@cnt] = getarg(.@f + 1);
+ .@cnt ++;
+ }
+ }
+
+ @menu = 255;
+ @menuret = -1;
+ select(.@menustr$);
+ if (@menu == 255)
+ return "";
+
+ @menu --;
+ if (@menu < 0 || @menu >= getarraysize(.@vals$))
+ return "";
+
+ @menuret$ = .@vals$[@menu];
+ return @menuret$;
+}
diff --git a/npc/functions/inventoryplace.txt b/npc/functions/inventoryplace.txt
new file mode 100644
index 00000000..c7eff88b
--- /dev/null
+++ b/npc/functions/inventoryplace.txt
@@ -0,0 +1,37 @@
+// Evol functions.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Check if the player have enough place on his inventory to accept new items with arguments:
+// getarg(even numbers) item ID,
+// getarg(odd numbers) number of items,
+
+function script inventoryplace {
+
+ .@argc = getargcount();
+
+ if (.@argc % 2 != 0)
+ {
+ consolemes(CONSOLEMES_ERROR, "inventoryplace: Wrong argument count.");
+ close;
+ }
+
+ for (.@i = .@j = 0; .@i < .@argc; .@i += 2)
+ {
+ setarray .@item[.@j], getarg(.@i);
+ setarray .@amount[.@j], getarg(.@i + 1);
+ ++.@j;
+ }
+
+ if (!checkweight2(.@item, .@amount))
+ {
+ narrator S_FIRST_BLANK_LINE,
+ l("It looks like you can't carry anything else for now."),
+ l("You should come back when you have some free space.");
+
+ close;
+ }
+
+ return true;
+}
diff --git a/npc/functions/legacy.txt b/npc/functions/legacy.txt
new file mode 100644
index 00000000..5f5ad026
--- /dev/null
+++ b/npc/functions/legacy.txt
@@ -0,0 +1,238 @@
+// NOTE: no script other than the functions in this file should EVER access
+// ##LEGACY[] or LEGACY[]
+
+/**
+ * gets the timestamp of when the attached or provided account was ported from
+ * the Legacy snapshot through Vault
+ *
+ * Example:
+ * getlegacyporttime();
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return timestamp (seconds)
+ */
+function script getlegacyporttime {
+ // we dereference the variable (+ 0) to avoid accidental assignment
+ return 0+ getvariableofpc(##LEGACY[1], nameid2id(getarg(0, "")), 0);
+}
+
+/**
+ * gets the former account id that was assigned to the attached or provided
+ * account on the Legacy server
+ *
+ * Example:
+ * getlegacyaccountid();
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return former account id
+ */
+function script getlegacyaccountid {
+ // we dereference the variable (+ 0) to avoid accidental assignment
+ return 0+ getvariableofpc(##LEGACY[0], nameid2id(getarg(0, "")), 0);
+}
+
+/**
+ * checks whether the attached or provided account is a former Legacy account
+ *
+ * Example:
+ * islegacyaccount()
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return true/false
+ */
+function script islegacyaccount {
+ return getlegacyaccountid(getarg(0, "")) > 0;
+}
+
+/**
+ * gets the former char id that was assigned to the attached or provided
+ * character on the Legacy server
+ *
+ * Example:
+ * getlegacycharid();
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return former char id
+ */
+function script getlegacycharid {
+ // we dereference the variable (+ 0) to avoid accidental assignment
+ return 0+ getvariableofpc(LEGACY[0], nameid2id(getarg(0, "")), 0);
+}
+
+/**
+ * checks whether the attached or provided character is a former Legacy char
+ *
+ * Example:
+ * islegacychar()
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return true/false
+ */
+function script islegacychar {
+ return getlegacycharid(getarg(0, "")) > 0;
+}
+
+/**
+ * gets the timestamp of when the attached or provided account completed the
+ * tutorial on the Legacy server
+ *
+ * Example:
+ * getlegacytuttime("player name")
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return timestamp (seconds)
+ */
+function script getlegacytuttime {
+ .@tut_var = getvariableofpc(LEGACY[2], nameid2id(getarg(0, "")), 0);
+ return .@tut_var < 0x7F ? 0 : .@tut_var;
+}
+
+/**
+ * gets the level the attached or provided player had on the Legacy server at
+ * snapshot time
+ *
+ * Example:
+ * getlegacylevel("player name")
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return base level
+ */
+function script getlegacylevel {
+ return bitwise_get(getvariableofpc(LEGACY[1], nameid2id(getarg(0, "")), 0), 0x000000FF, 0);
+}
+
+/**
+ * gets the boss points the attached or provided player had on the Legacy server
+ * at snapshot time
+ *
+ * Example:
+ * getlegacybosspoints("player name")
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return boss points
+ */
+function script getlegacybosspoints {
+ return bitwise_get(getvariableofpc(LEGACY[1], nameid2id(getarg(0, "")), 0), 0x7FFFFF00, 8);
+}
+
+
+
+// the functions below can be used to mimic a Legacy account for local testing
+
+
+/**
+ * mimics a legacy account for local testing
+ *
+ * Example:
+ * setfakelegacyaccount("player name");
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @param 1? - legacy level (defaults to 99)
+ * @param 2? - legacy boss points (defaults to 5000)
+ * @return true/false
+ */
+function script setfakelegacyaccount {
+ if (!debug) {
+ consolemes(CONSOLEMES_ERROR, "setfakelegacyaccount() can only be used in debug mode");
+ return false;
+ }
+
+ .@acc = nameid2id(getarg(0, ""));
+
+ if (.@acc < 1) {
+ // player not found
+ return false;
+ }
+
+ // set the legacy account id to the current account id
+ set(getvariableofpc(##LEGACY[0], .@acc), .@acc);
+
+ // set the port time to yesterday
+ set(getvariableofpc(##LEGACY[1], .@acc), time_from_days(-1));
+
+ // set the legacy tut var to 180 days ago
+ set(getvariableofpc(LEGACY[2], .@acc), time_from_days(-180));
+
+ // set the legacy level
+ bitwise_set(getvariableofpc(LEGACY[1], .@acc), 0x000000FF, 0, getarg(1, 99));
+
+ // set the legacy boss points
+ bitwise_set(getvariableofpc(LEGACY[1], .@acc), 0x7FFFFF00, 8, getarg(2, 5000));
+ return true;
+}
+
+/**
+ * gets the inventory the attached or provided char had on the Legacy server at
+ * snapshot time
+ *
+ * Example:
+ * .@size = getlegacyinventory(.@item, .@amount);
+ *
+ * @param 0 - a reference to an array variable to hold the item ids
+ * @param 1 - a reference to an array variable to hold the item qty
+ * @param 2? - char name / account id (defaults to attached player)
+ * @return number of entries added to the arrays
+ */
+function script getlegacyinventory {
+ .@char = getlegacycharid(getarg(2, ""));
+
+ if (.@char < 1) {
+ consolemes(CONSOLEMES_ERROR, "getlegacyinventory: target legacy character not found");
+ return 0;
+ }
+
+ if ((getdatatype(getarg(0)) & (DATATYPE_VAR | DATATYPE_INT)) == 0) {
+ consolemes(CONSOLEMES_ERROR, "getlegacyinventory: first argument should be an integer array");
+ return 0;
+ }
+
+ if ((getdatatype(getarg(1)) & (DATATYPE_VAR | DATATYPE_INT)) == 0) {
+ consolemes(CONSOLEMES_ERROR, "getlegacyinventory: second argument should be an integer array");
+ return 0;
+ }
+
+ freeloop(true);
+ .@rows = query_sql(sprintf("SELECT nameid, amount FROM legacy.inventory WHERE char_id = '%d';", .@char),
+ getarg(0), getarg(1));
+ freeloop(false);
+
+ return .@rows;
+}
+
+/**
+ * gets the storage the attached or provided account had on the Legacy server at
+ * snapshot time
+ *
+ * Example:
+ * .@size = getlegacystorage(.@item, .@amount);
+ *
+ * @param 0 - a reference to an array variable to hold the item ids
+ * @param 1 - a reference to an array variable to hold the item qty
+ * @param 2? - char name / account id (defaults to attached player)
+ * @return number of entries added to the arrays
+ */
+function script getlegacystorage {
+ .@acc = getlegacyaccountid(getarg(2, ""));
+
+ if (.@acc < 1) {
+ consolemes(CONSOLEMES_ERROR, "getlegacystorage: target legacy account not found");
+ return 0;
+ }
+
+ if ((getdatatype(getarg(0)) & (DATATYPE_VAR | DATATYPE_INT)) == 0) {
+ consolemes(CONSOLEMES_ERROR, "getlegacystorage: first argument should be an integer array");
+ return 0;
+ }
+
+ if ((getdatatype(getarg(1)) & (DATATYPE_VAR | DATATYPE_INT)) == 0) {
+ consolemes(CONSOLEMES_ERROR, "getlegacystorage: second argument should be an integer array");
+ return 0;
+ }
+
+ freeloop(true);
+ .@rows = query_sql(sprintf("SELECT nameid, amount FROM legacy.storage WHERE account_id = '%d';", .@acc),
+ getarg(0), getarg(1));
+ freeloop(false);
+
+ return .@rows;
+}
diff --git a/npc/functions/legiontalk.txt b/npc/functions/legiontalk.txt
new file mode 100644
index 00000000..25004c07
--- /dev/null
+++ b/npc/functions/legiontalk.txt
@@ -0,0 +1,66 @@
+// Evol functions.
+// Authors:
+// Akko Teru
+// Reid
+// Qwerty Dragon
+// Description:
+// Tell a random sentence suited to Aemil's Legion in Artis.
+
+function script legiontalk {
+
+ switch (rand(15))
+ {
+ case 0:
+ npctalkonce(l("Do I look like a tree? I feel like one."));
+ //speech(
+ // l("Do you feel too weak even to do damage to this areas wishy-washy wildlife?"),
+ // l("Then concentrate your anger upon the trees hereabouts, you will gain experience whilst leveling your sword skill on them."),
+ // l("Oh, and a fruit may even fall for you if you are lucky! But stay alert to pick up your drops."));
+ //close;
+ break;
+ case 1:
+ npctalkonce(l("I'm a little busy right now."));
+ break;
+ case 2:
+ npctalkonce(l("Not in the mood to chat."));
+ break;
+ case 3:
+ npctalkonce(l("My breath smells bad."));
+ break;
+ case 4:
+ npctalkonce(l("Don't distract me, I have to stay alert."));
+ break;
+ case 5:
+ npctalkonce(l("Give me some space."));
+ break;
+ case 6:
+ npctalkonce(l("Can you please go away?"));
+ break;
+ case 7:
+ npctalkonce(l("Can't talk right now, I'm on patrol duty."));
+ break;
+ case 8:
+ npctalkonce(l("What're you looking at?!"));
+ break;
+ case 9:
+ npctalkonce(l("I can't stay here and talk all day. I have a job to do."));
+ break;
+ case 10:
+ npctalkonce(l("Keep moving!"));
+ break;
+ case 11:
+ npctalkonce(l("So you think you're tough? A warrior must also be loyal and patient."));
+ break;
+ case 12:
+ emotion E_LOOKAWAY;
+ break;
+ case 13:
+ npctalkonce(l("Practice! There are no secrets to becoming a warrior."));
+ break;
+ case 14:
+ npctalkonce(l("There is no honor in fighting a weak opponent."));
+ break;
+ }
+
+ return;
+}
diff --git a/npc/functions/libquest.txt b/npc/functions/libquest.txt
new file mode 100644
index 00000000..4799eb1d
--- /dev/null
+++ b/npc/functions/libquest.txt
@@ -0,0 +1,104 @@
+// Evol scripts for simplified quest development.
+// Author:
+// Livio
+
+/*
+ @brief Prints the list of quest ingredients on the NPC window
+ @param Array with items IDs
+ @param Array with relative amount required
+ @returns nothing
+*/
+function script printIngredients {
+ for (.@i = 0; .@i < getarraysize(getarg(0)); .@i++) {
+ mesf(" - %d %s", getelementofarray(getarg(1), .@i), getitemlink(getelementofarray(getarg(0), .@i)));
+ }
+ return;
+}
+
+/*
+ @brief Checks if player has items required
+ @param Array with required items IDs
+ @param Array with relative amount required
+ @returns false if player doesn't have required items
+*/
+function script checkForItems {
+ for (.@i = 0; .@i < getarraysize(getarg(0)); .@i++) {
+ // If even a single thing is missing abort immediately
+ if(getelementofarray(getarg(1), .@i) > countitem(getelementofarray(getarg(0), .@i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ @brief Craft an item from some other items. All input items got deleted.
+ @param Array with required items IDs
+ @param Array with relative amount required
+ @param output item IDs
+ @param output amount
+ @returns 0 if successful, 1 if player lack ingredients, 2 if overburdened, 255 code error
+*/
+function script craftFromPlayer {
+ // Check input parameter amount
+ if (getargcount() != 4) return 255;
+
+ // Check item amounts
+ if (!checkForItems(getarg(0), getarg(1))) return 1;
+
+ // Check if player is able to carry output from crafting
+ if (!checkweight(getarg(2), getarg(3))) return 2;
+ else getitem(getarg(2), getarg(3));
+
+ // Delete Items from player inventory
+ for (.@i = getarrayindex(getarg(0)); .@i < getarraysize(getarg(0)); .@i++) {
+ delitem(getelementofarray(getarg(0), .@i), getelementofarray(getarg(1), .@i));
+ }
+
+ return 0;
+}
+
+/*
+ @brief Craft an item from some other items. All input items will be deleted in case of success.
+ @param Array with required items IDs
+ @param Array with relative amount required
+ @param output item IDs
+ @param output amount
+ @param NPC question about ingredients
+ @param NPC answer if successful
+ @param NPC answer if player lacks ingredients
+ @param NPC answer if player is overburdened
+ @returns true if successful
+*/
+function script NPCcrafting {
+ speech
+ getarg(4);
+ if (askyesno() == ASK_NO) {
+ mesq l("Come on, move!");
+ close;
+ } else {
+ switch(craftFromPlayer(getarg(0), getarg(1), getarg(2), getarg(3))) {
+ case 0:
+ mesq getarg(5);
+ return true;
+ break;
+
+ case 1:
+ mesq getarg(6);
+ // FIXME - Gather proper variables
+ printIngredients(getarg(0), getarg(1));
+ break;
+
+ case 2:
+ mesq getarg(7);
+ break;
+
+ case 255:
+ mesq l("[BUG ENCOUNTERED] Dammit...");
+ break;
+
+ default:
+ }
+ }
+ return false;
+} \ No newline at end of file
diff --git a/npc/functions/lockpicks.txt b/npc/functions/lockpicks.txt
new file mode 100644
index 00000000..6a3c55f7
--- /dev/null
+++ b/npc/functions/lockpicks.txt
@@ -0,0 +1,193 @@
+// TMW2/LoF Script
+// Author:
+// Jesusalva
+// Description:
+// Lockpicking core
+
+// Important variables:
+// THIEF_EXP
+// Experience on Thief Tree
+// THIEF_RANK
+// Position on the Thief Tree
+
+// LockPicking(num_pins, max_pins, min_rank=num_pins)
+// Returns 0 upon failure, 1 upon success
+// Closes script if an error happen or if you give up / cannot try.
+//
+// The 'next' is upon script responsability
+// Maximum pin number is infinite. Maximum Pin Positiors range from 2~5.
+// If you fail, you can end up having to start again. If you fail too much,
+// you'll be caught!
+function script LockPicking {
+ // If you don't have a LockPick, you can't do this (useless)
+ if (!countitem(Lockpicks)) {
+ mesc l("You need a @@ to try this.", getitemlink(Lockpicks)), 1;
+ close;
+ }
+
+ .@d=getarg(0,1);
+ .@m=getarg(1,3);
+ .@minrank=getarg(2, .@d);
+
+ // Invalid Argument (kill script)
+ if (.@d < 1 || .@m < 2 || .@m > 5)
+ end;
+
+ // You must be rank (number of locks - 1) to try
+ if (THIEF_RANK+1 < .@minrank) {
+ mesc l("This lock is beyond your current capacity."), 1;
+ close;
+ }
+
+ // Create @pins array (the answer)
+ for (.@i=0; .@i < .@d;.@i++)
+ @pins[.@i] = rand2(1,.@m);
+
+ // Check if you'll try to open it.
+ mesc l("This lock is simple, maybe with your thief skills you can manage to pry it open. But beware, you can end up in jail!");
+ mesc l("Will you try to unlock it?");
+ if (askyesno() == ASK_NO)
+ close;
+
+ // Setup your attempt
+ delitem Lockpicks, 1;
+ @pos=0;
+ @chance=min(.@d*.@m-1, THIEF_RANK+.@d);
+ mesc l("You insert the hook pick inside the lock, and, without applying any tension, you discover there are only @@ pins to set.", .@d);
+
+ // You have as many attempts as pins and appliable strenghts.
+ // Each thief rank grants you an extra attempt.
+ // Each pin takes one attempt.
+ // It's not multiplied, so 3 pins with 3 positions: 6 chances, 9 possibilities.
+ // There's no penalty, but the attempt is counted working or not!
+ // Remember if you fail, all previous pins will be cleared (@pos)
+ do {
+ mesc l("You are trying to open the @@th pin. What will to do?", @pos+1);
+
+ menuint
+ rif(.@m >= 4, l("Apply no pressure")), 4,
+ rif(.@m >= 2, l("Apply soft pressure")), 2,
+ rif(.@m >= 1, l("Apply normal pressure")), 1,
+ rif(.@m >= 3, l("Apply strong pressure")), 3,
+ rif(.@m >= 5, l("Apply very strong pressure")), 5,
+ l("Give up!"), 0;
+
+ if (!@menuret) {
+ // 50% chance to save the lockpick
+ if (rand2(2) == 1)
+ getitem Lockpicks, 1;
+ else
+ dispbottom l("The lockpick broke.");
+ close;
+ }
+
+ // Is your guess correct?
+ if (@pins[@pos] == @menuret) {
+ mesc l("*click*");
+ @pos+=1;
+ } else {
+ mesc l("This didn't work. All pins are now unset!");
+ @pos=0;
+ @chance-=1;
+ // We don't need to clear console, each successful attempt IS counted.
+ // Therefore, unsetting 3 pins means you must do 3 new attempts!!
+ // The biggie is that you're running against time, here!!!
+ if (@chance < .@d && rand2(0, THIEF_RANK))
+ mesc l("Your thief instincts suggest you to hurry."), 1;
+ }
+
+ if (@chance <= 0)
+ break;
+
+ if (@pos >= .@d) {
+ // 33% chance to save the lockpick
+ if (rand2(3) == 1)
+ getitem Lockpicks, 1;
+ else
+ dispbottom l("The lockpick broke.");
+
+ // Get EXP and inform the success
+ if (THIEF_RANK)
+ THIEF_EXP += max(0, .@d*.@m-THIEF_RANK);
+ return 1;
+ }
+ } while (true);
+
+ // Failed
+ if (THIEF_RANK)
+ THIEF_EXP += 1;
+ return 0;
+}
+
+// Script helper to say if you were arrested or not
+function script ArrestedChances {
+ .@runaway=cap_value(readbattleparam(getcharid(3), UDT_LUK)+readbattleparam(getcharid(3), UDT_AGI), 0, 200); // 20%
+ .@runaway+=125; // 12.5% base chance
+ .@runaway+=cap_value(THIEF_RANK*15, 0, 100); // real max 7.5%
+ // Max runaway chance: 40%
+ if (rand2(1000) < .@runaway)
+ return false;
+ return true;
+}
+
+// Script helper to actually arrest you. TODO: Arrest anyone
+// ArrestPlayer ( time-in-minutes )
+function script ArrestPlayer {
+ .@t=getarg(0);
+
+ // We can't do anything without a player o.o
+ if (!playerattached())
+ return;
+
+ // You're already jailed so we do nothing and fail silently
+ if (getstatus(SC_JAILED)) {
+ return;
+ }
+
+ // Okay, we can arrest you
+ // TODO: Arrest player, preferably without GM commands D:
+ // (would then take an extra argument: map)
+ atcommand("@jailfor "+.@t+"mn "+strcharinfo(0));
+
+ // Notification
+ dispbottom l("You were arrested; Use %s for information about how long you will spend here.", b("@jailtime"));
+ return;
+}
+
+/*
+// Main script from Moubootaur Legends Vaults
+// LootableVault(tier, level, variable)
+function script LootableVault {
+ .@tier=getarg(0)+1;
+ .@level=getarg(1);
+ .@var$=getarg(2);
+ mesn;
+ mesq l("There's a shiny safe here. How much money is inside? Nobody is looking at you, great!");
+ // 2*3 = 6 possibilities, 5 attempts
+ if (LockPicking(.@tier, .@level)) {
+ Zeny=Zeny+getd("$VAULT_"+.@var$);
+ setd("$VAULT_"+.@var$, 40);
+ mesn;
+ mesq l("Booty!");
+ } else {
+ mesn;
+ .@inch=(Zeny/100);
+ Zeny-=.@inch;
+ setd("$VAULT_"+.@var$, getd("$VAULT_"+.@var$)+.@inch);
+ if (ArrestedChances()) {
+ mesc l("Arrested!");
+ atcommand("@jailfor 5mn "+strcharinfo(0));
+ } else {
+ if (is_night())
+ .@p$=l("The darkness of night gives you cover.");
+ else
+ .@p$=l("Your agile legs and sheer luck allows you to outrun the cops.");
+ mesc l("You run as far as you could. %s", .@p$);
+ warp "000-1", 22, 22;
+ }
+ }
+ return;
+}
+*/
+
+
diff --git a/npc/functions/main.txt b/npc/functions/main.txt
new file mode 100644
index 00000000..8029f3eb
--- /dev/null
+++ b/npc/functions/main.txt
@@ -0,0 +1,445 @@
+// Evol functions.
+// Authors:
+// 4144
+// Jesusalva
+// Travolta
+// Description:
+// Build in functions.
+
+/**
+ * checks whether the given argument is a char name or account id
+ * and tries to convert it to an account id
+ *
+ * @arg 0 - char name or account id
+ * @return the account id
+ */
+function script nameid2id {
+ if ((getdatatype(getarg(0, "")) & DATATYPE_STR) != 0) {
+ if (getarg(0, "") == "") {
+ return playerattached();
+ } else {
+ return getcharid(CHAR_ID_ACCOUNT, getarg(0));
+ }
+ } else if (getarg(0) == 0) {
+ return playerattached();
+ } else {
+ return getarg(0);
+ }
+}
+
+function script menuimage {
+ return getarg(0) + "|" + getarg(1);
+}
+
+function script menuaction {
+ return "[" + getarg(0) + "]";
+}
+
+function script mesn {
+ if (getargcount() > 0)
+ {
+ .@s$ = "[" + getarg(0) + "]";
+ }
+ else
+ {
+ .@s$ = "[" + strnpcinfo(1) + "]";
+ }
+ mes .@s$;
+ return;
+}
+
+function script mesq {
+ mes "\"" + getarg(0)+ "\"";
+ return;
+}
+
+function script g {
+ consolemes(CONSOLEMES_ERROR, "Deprecated function \"g\" used, results are not reliable.");
+ return rand(1000) % 2 ? getarg(0) : getarg(1);
+}
+
+function script b {
+ return "##B" + getarg(0) + "##b";
+}
+
+function script col {
+ .@color = getarg(1);
+ if (.@color < 0) .@color = 0;
+ if (.@color > 9) .@color = 9;
+ return "##" + .@color + getarg(0) + "##0";
+}
+
+function script mesc {
+ return mes(col(getarg(0, ""), getarg(1, 9)));
+}
+
+// *showimage("<file>");
+// Displays an image in the NPC window. If no file extension is provided, it is
+// assumed to be a PNG file. The image path is relative to client-data/graphics.
+// example:
+// showimage("guiicons/flags/fr");
+function script showimage {
+ .@file$ = getarg(0);
+
+ if (!endswith(getarg(0), ".jpg") && !endswith(getarg(0), ".png")) {
+ .@file$ += ".png";
+ }
+
+ if (charat(getarg(0), 0) == "/") {
+ .@file$ = delchar(.@file$, 0); // absolute path from root of client-data
+ } else if (!startswith(getarg(0), "help/") && !startswith(getarg(0), "graphics/") ) {
+ .@file$ = "graphics/" + .@file$; // assume relative to graphics/
+ }
+
+ return mesf("~~~%s~", .@file$);
+}
+
+function script adddefaultskills {
+ if (getskilllv(NV_BASIC) < 6)
+ {
+ skill NV_BASIC, 6, 0;
+ }
+ return;
+}
+
+function script addremovemapmask {
+ setmapmask getarg(0), (getmapmask(getarg(0)) | (getarg(1) + getarg(2))) ^ getarg(2);
+ return;
+}
+
+// Function to show narrator text. Accepts string args.
+// If first arg is a number N, then it represents bit flags.
+// Bit flags :
+// S_FIRST_BLANK_LINE -- blank line at beginning
+// S_LAST_BLANK_LINE -- blank line at the end
+// S_LAST_NEXT -- use last "next();"
+// S_NO_NPC_NAME -- don't use first "mesn();"
+// S_LAST_CLOSE -- use last "close2();
+function script narrator {
+ .@start = 0;
+ .@argc = getargcount();
+ .@flags = 0;
+
+ if (.@argc > 1 && (getdatatype(getarg(0)) & DATATYPE_INT) != 0) {
+ .@start = 1;
+ .@flags = getarg(0);
+ }
+
+ if ((.@flags & S_FIRST_BLANK_LINE) != 0) {
+ mes("");
+ }
+
+ if ((.@flags & S_NO_NPC_NAME) == 0) {
+ mesn(l("Narrator"));
+ }
+
+ for (.@i = .@start; .@i < .@argc; .@i++) {
+ mes(col(getarg(.@i), 9));
+
+ if (.@i < .@argc - 1) {
+ next();
+ }
+ }
+
+ if ((.@flags & S_LAST_BLANK_LINE) != 0) {
+ mes("");
+ }
+
+ if ((.@flags & S_LAST_NEXT) != 0) {
+ next();
+ } else if ((.@flags & S_LAST_CLOSE) != 0) {
+ close2();
+ }
+
+ return;
+}
+
+// Function to show NPC speech. Accepts string args.
+// If first arg is a number N, then it represents bit flags.
+// Bit flags :
+// 0x1 -- blank line at beginning
+// 0x2 -- blank line at the end
+// 0x4 -- use last "next;"
+// 0x8 -- don't use first "mesn;"
+function script speech {
+ .@start = 0;
+ .@argc = getargcount();
+ .@flags = 0;
+
+ if (.@argc > 1 && !isstr(getarg(0)))
+ {
+ .@start = 1;
+ .@flags = getarg(0);
+ }
+
+ if (.@flags & 0x1)
+ mes "";
+
+ if (!(.@flags & 0x8))
+ mesn;
+
+ for (.@i = .@start; .@i < .@argc; .@i++)
+ {
+ mesq getarg(.@i);
+
+ if (.@i < .@argc - 1)
+ next;
+ }
+
+ if (.@flags & 0x4)
+ next;
+ else if (.@flags & 0x2)
+ mes "";
+
+ return;
+}
+
+// Show debug message if .debug variable of NPC is set to 1
+function script npcdebug {
+ if (getvariableofnpc(.debug, strnpcinfo(3)))
+ consolemes(CONSOLEMES_DEBUG, strnpcinfo(3) + ": " + getarg(0));
+ return;
+}
+
+function script askyesno {
+ .@sel = select(menuaction(l("Yes")),
+ menuaction(l("No")));
+ mes "";
+ return .@sel;
+}
+
+// Argument:
+// 0 Quest variable
+// 1 Current value
+// 2 Next value
+function script compareandsetq {
+ if (getq(getarg(0)) == getarg(1))
+ {
+ setq getarg(0), getarg(2);
+ return true;
+ }
+ return false;
+}
+
+// Use a delay to prevent spams from NPC that display text without the
+// use of (a) close/next function(s).
+// Argument:
+// 0 Text to display
+// 1 Lock delay (default = 1)
+// 2 Message function: (default = 0)
+// 0 = npctalk3
+// 1 = npctalk
+// 2 = message
+function script npctalkonce {
+ // lock mechanism
+ switch (getarg(2, 0))
+ {
+ case 1:
+ if (gettimetick(2) <= getvariableofnpc(.talk_lock, strnpcinfo(NPC_NAME_UNIQUE)))
+ return false;
+ set(getvariableofnpc(.talk_lock, strnpcinfo(NPC_NAME_UNIQUE)), gettimetick(2) + getarg(1, 1));
+ break;
+ default:
+ if (gettimetick(2) <= @NPC_TALK_LOCK[getnpcid()])
+ return false;
+ @NPC_TALK_LOCK[getnpcid()] = gettimetick(2) + getarg(1, 1);
+ }
+
+ // talk mechanism
+ switch (getarg(2, 0))
+ {
+ case 0: npctalk3(getarg(0)); break;
+ case 1: npctalk(getarg(0)); break;
+ case 2: message(strcharinfo(0), getarg(0));
+ }
+
+ return true;
+}
+
+function script getquestlink {
+ return "[@@q" + getarg(0) + "|@@]";
+}
+
+function script getmonsterlink {
+ return "[@@m" + getarg(0) + "|@@]";
+}
+
+function script getpetlink {
+ return "[@@p" + getarg(0) + "|@@]";
+}
+
+function script getmercenarylink {
+ return "[@@M" + getarg(0) + "|@@]";
+}
+
+function script gethomunculuslink {
+ return "[@@h" + getarg(0) + "|@@]";
+}
+
+// Returns the player race in plain text
+// GETRACE_RACE - returns player race (default)
+// GETRACE_SKIN - returns player skin
+// GETRACE_FULL - returns player skin + race
+// Can take an optional 2nd param with the class
+// get_race( {Flag, {Class}} )
+function script get_race {
+ .@m=getarg(0, GETRACE_RACE);
+ .@g=getarg(1, Class);
+
+ // We also allow this to run without player attached for... science.
+ if (playerattached())
+ {
+ setarray .@allraces$, l("Human"), l("Human"), l("Human"),
+ l("Ukar"), l("Ukar"),
+ l("Tritan"), l("Tritan"),
+ l("Raijin"), l("Raijin"),
+ l("Kralog"), l("Kralog");
+ setarray .@allskins$, l("Kaizei"), l("Argaes"), l("Tonori"),
+ l("Cave"), l("Mountain"),
+ l("Sea"), l("Lake"),
+ l("Light"), l("Dark"),
+ l("Fire"), l("Frost");
+ }
+ else
+ {
+ setarray .@allraces$, ("Human"), ("Human"), ("Human"),
+ ("Ukar"), ("Ukar"),
+ ("Tritan"), ("Tritan"),
+ ("Raijin"), ("Raijin"),
+ ("Kralog"), ("Kralog");
+ setarray .@allskins$, ("Kaizei"), ("Argaes"), ("Tonori"),
+ ("Cave"), ("Mountain"),
+ ("Sea"), ("Lake"),
+ ("Light"), ("Dark"),
+ ("Fire"), ("Frost");
+ }
+
+ if (.@m == GETRACE_RACE)
+ return .@allraces$[.@g];
+ else if (.@m == GETRACE_SKIN)
+ return .@allskins$[.@g];
+ else
+ return .@allskins$[.@g] + " " + .@allraces$[.@g];
+}
+
+// Clear output of getinventorylist()
+// delinventorylist()
+function script delinventorylist {
+ deletearray @inventorylist_id;
+ deletearray @inventorylist_amount;
+ deletearray @inventorylist_equip;
+ deletearray @inventorylist_refine;
+ deletearray @inventorylist_identify;
+ deletearray @inventorylist_attribute;
+ deletearray @inventorylist_card1;
+ deletearray @inventorylist_card2;
+ deletearray @inventorylist_card3;
+ deletearray @inventorylist_card4;
+ deletearray @inventorylist_expire;
+ deletearray @inventorylist_bound;
+ @inventorylist_count=0;
+ return;
+}
+
+// isin( map, x1, y1, {[x2, y2][radius]} )
+function script isin {
+ if (getmapxy(.@mapName$, .@xpos, .@ypos, 0) != 0)
+ return false;
+ if (.@mapName$ != getarg(0))
+ return false;
+
+ if (getarg(4,-1) < 0) {
+ // Radius Based
+ if (.@xpos >= getarg(1)-getarg(3) && .@xpos <= getarg(1)+getarg(3) && .@ypos >= getarg(2)-getarg(3) && .@ypos <= getarg(2)+getarg(3))
+ return true;
+ } else {
+ // Coordinate based
+ if (.@xpos >= getarg(1) && .@xpos <= getarg(3) && .@ypos >= getarg(2) && .@ypos <= getarg(4))
+ return true;
+ }
+ return false;
+}
+
+// Shortcut for getmapname()
+function script getmap {
+ return getmapname();
+}
+
+// Quest Rewards
+// quest_xp(maxLevel, reward, {multiplier=1})
+function script quest_xp {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ if (BaseLevel <= .@maxLevel) {
+ getexp .@reward*.@mult, 0;
+ return;
+ }
+ // You'll forsake 2% every over level
+ .@mult*=100;
+ .@mult-=((BaseLevel - .@maxLevel) * 2);
+ .@mult=max(10, .@mult);
+ getexp .@reward*.@mult/100, 0;
+ return;
+}
+
+// quest_jxp(maxLevel, reward, {multiplier=1})
+function script quest_jxp {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ if (BaseLevel < .@maxLevel) {
+ getexp 0, .@reward*.@mult;
+ return;
+ }
+ // You'll forsake 2% every over level
+ .@mult*=100;
+ .@mult-=((BaseLevel - .@maxLevel) * 2);
+ .@mult=max(10, .@mult);
+ getexp 0, .@reward*.@mult/100;
+ return;
+}
+
+// quest_gp(maxLevel, reward, {multiplier=1})
+function script quest_gp {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ if (BaseLevel <= .@maxLevel) {
+ Zeny+=.@reward*.@mult;
+ return;
+ }
+ // You'll forsake 2% every over level
+ .@mult*=100;
+ .@mult-=((BaseLevel - .@maxLevel) * 2);
+ .@mult=max(10, .@mult);
+ Zeny+=.@reward*.@mult/100;
+ return;
+}
+
+// quest_item(maxLevel, item, {amount=1}, {bound=0})
+function script quest_item {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ .@bind=getarg(3, 0);
+ // Item will not be obtained if you are overlevel
+ if (BaseLevel > .@maxLevel && .@mult <= 1)
+ return;
+ // If it comes in pairs, you'll only get 1
+ if (BaseLevel > .@maxLevel)
+ .@mult=1;
+ // Obtain item bound if needed
+ if (.@bind)
+ getitembound .@reward, .@mult, .@bind;
+ else
+ getitem .@reward, .@mult;
+ return;
+}
+
+
+
diff --git a/npc/functions/manhole.txt b/npc/functions/manhole.txt
new file mode 100644
index 00000000..3af18537
--- /dev/null
+++ b/npc/functions/manhole.txt
@@ -0,0 +1,73 @@
+// TMW2 Script
+// Authors:
+// Jesusalva
+//
+// Description:
+// Handles Artis manholes
+// Relies on getmap, be sure coords are enough compatible
+// ie. Leave a 2x2 area free of collision in the target coordinates
+// Heights weren't checked
+
+// manhole_interact( dest_map )
+// Carries over getmapxy() for NPC
+// This is for Artis and thus, hackish.
+// Return Codes:
+// -1 : Tried to enter Sewers
+// >0 : ID of dropped item (in case it must be caught)
+
+function script manhole_interact {
+ .@dest_map$=getarg(0);
+ getmapxy(.@m$, .@x, .@y, UNITTYPE_NPC);
+
+ narrator(S_LAST_BLANK_LINE | S_LAST_NEXT,
+ l("You hear some creeping and crawling sounds from the murkiness below."),
+ l("..."));
+
+ select
+ l("Do you want to leave it alone?"),
+ rif(getq(ArtisQuests_MonaDad), l("Do you want to enter in sewer?")),
+ l("Do you want to throw something inside?");
+
+ switch (@menu) {
+ case 1:
+ close; break;
+ case 2:
+ return -1; break;
+ case 3:
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+
+ .@id = requestitem();
+
+ // If ID is invalid
+ if (.@id < 1) {
+ mesc l("You give up.");
+ close;
+ }
+
+ // If there's not enough items, it is bound, it cannot be traded/dropped/sold, etc.
+ if (countitem(.@id) < 1 || checkbound(.@id) || getiteminfo(.@id, ITEMINFO_TRADE)) {
+ mesc l("You cannot drop this item!");
+ close;
+ }
+
+ // Delete item and spawn it on the equivalent map
+ delitem .@id, 1;
+ makeitem .@id, 1, .@dest_map$, .@x+rand(-2, 2), .@y+rand(-2, 2);
+
+ // May spawn a monster if it is food (33% odds)
+ if (getiteminfo(.@id, ITEMINFO_TYPE) == IT_HEALING && rand(1,3) == 3) {
+ // Would be nice to customize but not needed atm
+ // 1 mob for every 30 levels (level 99 players spawn 4 mobs)
+ // Note that food type is currently disregarded (and it accepts any healing item)
+ .@monsterId=any(Slime, Croc, LittleBlub, CaveMaggot);
+ .@mobGID = monster(.@m$, .@x, .@y, strmobinfo(1, .@monsterId), .@monsterId, (BaseLevel/30)+1);
+ unitattack(.@mobGID, getcharid(CHAR_ID_ACCOUNT)); // "It's not aggressive"? We don't care.
+ }
+
+ return .@id; break;
+ }
+
+
+
+}
+
diff --git a/npc/functions/masks.txt b/npc/functions/masks.txt
new file mode 100644
index 00000000..4b28bfc7
--- /dev/null
+++ b/npc/functions/masks.txt
@@ -0,0 +1,43 @@
+// Evol functions.
+// Author:
+// Reid
+// Jesusalva
+// Description:
+// Triggers functions to add and remove masks.
+// Variables:
+// 4 - Top Mask
+// 8 - Bottom Mask
+// Default mask: 13 (Top + Bottom + Display mask)
+
+// Artis Aemil's Legion
+
+function script artisALResetMask {
+ .@m=getmapmask("001-2-33");
+ sendmapmask(.@m);
+ return 0;
+}
+
+function script artisALTopMask {
+ addtimer 30, "artisALTopMaskDO::OnDoIt";
+ return 0;
+}
+
+function script artisALBottomMask {
+ addtimer 30, "artisALBottomMaskDO::OnDoIt";
+ return 0;
+}
+
+// Show bottom mask is the same as hiding top mask
+- script artisALBottomMaskDO NPC_HIDDEN,{
+OnDoIt:
+ .@m=getmapmask("001-2-33");
+ sendmapmask(.@m^4);
+}
+
+// Show top mask is the same as hiding bottom mask
+- script artisALTopMaskDO NPC_HIDDEN,{
+OnDoIt:
+ .@m=getmapmask("001-2-33");
+ sendmapmask(.@m^8);
+}
+
diff --git a/npc/functions/math.txt b/npc/functions/math.txt
new file mode 100644
index 00000000..357407da
--- /dev/null
+++ b/npc/functions/math.txt
@@ -0,0 +1,50 @@
+// Evol functions.
+// Authors:
+// 4144
+// Reid
+// Jesusalva
+// Description:
+// Math functions
+
+
+// abs(<int>)
+// returns the absolute value of the passed integer
+
+function script abs {
+ .@n = getarg(0);
+ return .@n >= 0 ? .@n : -.@n;
+}
+
+
+
+// lognbaselvl({<multiplicator>{, <min value>}})
+// returns BaseLevel * logn (BaseLevel * alpha).
+
+function script lognbaselvl {
+ .@alpha = getarg(0, 1);
+ .@min = getarg(1, 1);
+ .@ret = 0;
+ .@pc_level = BaseLevel * .@alpha;
+
+ while (.@pc_level >>= 1)
+ {
+ ++.@ret;
+ }
+ .@ret *= BaseLevel;
+
+ if (.@ret <= .@min)
+ {
+ .@ret = .@min;
+ }
+
+ return .@ret;
+}
+
+
+// result is: lower < target <= higher
+// is_between ( lower, higher, target)
+function script is_between {
+ .@val=getarg(2);
+ return (getarg(0) < .@val && getarg(1) >= .@val);
+}
+
diff --git a/npc/functions/mouboofunc.txt b/npc/functions/mouboofunc.txt
new file mode 100644
index 00000000..6129c083
--- /dev/null
+++ b/npc/functions/mouboofunc.txt
@@ -0,0 +1,89 @@
+// Evol functions.
+// Author:
+// Reid
+// Description:
+// Various scripts used in walking mouboo NPCs.
+
+function script moubootalk {
+ switch (rand(4))
+ {
+ case 0:
+ npctalkonce(l("Moooooo!"));
+ break;
+ case 1:
+ npctalkonce(l("Moo!"));
+ break;
+ case 2:
+ npctalkonce(l("Moooooooooooo!"));
+ break;
+ case 3:
+ npctalkonce(l("Moooo!"));
+ break;
+ }
+ return;
+}
+
+function script mouboocheckxy {
+ setarray .nearnpc$[0], "Mouboo#Artis0",
+ "Mouboo#Artis1",
+ "Mouboo#Artis2",
+ "Mouboo#Artis3",
+ "Taree";
+ for (.@size = 0; .@size < getarraysize(.nearnpc$); .@size++)
+ {
+ if (strcmp(.name$, .nearnpc$[.@size]) == 0)
+ {
+ continue;
+ }
+
+ .@npc_x = getvariableofnpc(.x, .nearnpc$[.@size]);
+ .@npc_y = getvariableofnpc(.y, .nearnpc$[.@size]);
+
+ if (.@npc_x == .x && .@npc_y == .y)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+function script moubootimer {
+ if (mouboocheckxy() && !isunitwalking())
+ {
+ movetonextpoint;
+ }
+ else if (rand(0,6) == 5)
+ {
+ if (!isunitwalking())
+ {
+ movetonextpoint;
+ }
+ }
+ initnpctimer;
+ end;
+}
+
+function script mouboograph {
+ initmovegraph "down_pos", 66, 79, 75, 86,
+ "left_pos", 66, 79, 75, 86,
+ "up_pos", 66, 79, 75, 86,
+ "right_pos", 66, 79, 75, 86;
+
+ setmovegraphcmd "down_pos", "left_pos", 1, "dir 2",
+ "down_pos", "up_pos", 1, "dir 4",
+ "down_pos", "right_pos", 1, "dir 6",
+ "left_pos", "down_pos", 1, "dir 0",
+ "left_pos", "up_pos", 1, "dir 4",
+ "left_pos", "right_pos", 1, "dir 6",
+ "up_pos", "down_pos", 1, "dir 0",
+ "up_pos", "left_pos", 1, "dir 2",
+ "up_pos", "right_pos", 1, "dir 6",
+ "right_pos", "down_pos", 1, "dir 0",
+ "right_pos", "left_pos", 1, "dir 2",
+ "right_pos", "up_pos", 1, "dir 4";
+
+ firstmove "wait 2", "down_pos";
+ initnpctimer;
+ end;
+}
diff --git a/npc/functions/music.txt b/npc/functions/music.txt
new file mode 100644
index 00000000..18a8fbe7
--- /dev/null
+++ b/npc/functions/music.txt
@@ -0,0 +1,87 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Gumi
+// Ledmitz
+// Description:
+// Music functions
+//
+// NOTE: This NPC uses the new public/private function call system to avoid
+// the use of doevent.
+// Syntax:
+// "jukebox"::HurnscaldPrompt(); → Makes a menuint for selecting hurns tracks
+// "jukebox"::JukeboxMusic(ID); → Changes music based on prompted ID
+// "jukebox"::BroadcastMusic(MAP, ID); → Changes music based on prompted ID
+// TODO: Check if you have the music unlocked? Bitmask? Array?
+
+- script jukebox 32767,{
+ end;
+
+// Helpers
+public function JukeboxMusic {
+ changeplayermusic $MUSIC_ARRAY$[getarg(0)] + ".ogg";
+ return;
+}
+
+public function BroadcastMusic {
+ changemusic getarg(0), $MUSIC_ARRAY$[getarg(1)] + ".ogg";
+ return;
+}
+
+// public function listing
+// * Hurnscald
+
+public function HurnscaldPrompt {
+ menuint
+ "Cancel", -1,
+ "Johanne - Forest of Birches", 0,
+ "Artis - Adventure Begins", 1,
+ "Argaes - Dariunas' Forest", 20,
+ "Hurnscald - Magick Real", 5;
+ mes "";
+ if (@menuret == -1)
+ close;
+ return @menuret;
+}
+
+// Initialize stuff which will be needed
+OnInit:
+ $MUSIC_ARRAY$[0] = "johanne";
+ $MUSIC_ARRAY$[1] = "artis";
+ $MUSIC_ARRAY$[2] = "ghoulish";
+ $MUSIC_ARRAY$[3] = "surreal";
+ $MUSIC_ARRAY$[4] = "ocean";
+ $MUSIC_ARRAY$[5] = "real";
+ $MUSIC_ARRAY$[6] = "academy";
+ $MUSIC_ARRAY$[7] = "bandit";
+ $MUSIC_ARRAY$[8] = "barbarians";
+ $MUSIC_ARRAY$[9] = "botcheck";
+ $MUSIC_ARRAY$[10] = "candor";
+ $MUSIC_ARRAY$[11] = "cavesong";
+ $MUSIC_ARRAY$[12] = "chilling";
+ $MUSIC_ARRAY$[13] = "cloudcall";
+ $MUSIC_ARRAY$[14] = "crypt";
+ $MUSIC_ARRAY$[15] = "despair";
+ $MUSIC_ARRAY$[16] = "dimond";
+ $MUSIC_ARRAY$[17] = "explorer";
+ $MUSIC_ARRAY$[18] = "faith";
+ $MUSIC_ARRAY$[19] = "fire";
+ $MUSIC_ARRAY$[20] = "forest";
+ $MUSIC_ARRAY$[21] = "graveyard";
+ $MUSIC_ARRAY$[22] = "hurns";
+ $MUSIC_ARRAY$[23] = "marine";
+ $MUSIC_ARRAY$[24] = "mystique";
+ $MUSIC_ARRAY$[25] = "nightcall";
+ $MUSIC_ARRAY$[26] = "nivalis";
+ $MUSIC_ARRAY$[27] = "ocean";
+ $MUSIC_ARRAY$[28] = "peace";
+ $MUSIC_ARRAY$[29] = "reid";
+ $MUSIC_ARRAY$[30] = "sewer";
+ $MUSIC_ARRAY$[31] = "store";
+ $MUSIC_ARRAY$[32] = "swamp";
+ $MUSIC_ARRAY$[33] = "thunderstorm";
+ $MUSIC_ARRAY$[34] = "waterlude";
+ $MUSIC_ARRAY$[35] = "xmas";
+ end;
+}
+
diff --git a/npc/functions/npcmove.txt b/npc/functions/npcmove.txt
new file mode 100644
index 00000000..612ab036
--- /dev/null
+++ b/npc/functions/npcmove.txt
@@ -0,0 +1,142 @@
+// Evol functions.
+// Author:
+// 4144
+// Description:
+// Moving npc utility functions
+// Variables:
+// none
+
+function script initpath {
+ deletearray getvariableofnpc(.movepathcmd$, strnpcinfo(3));
+ deletearray getvariableofnpc(.movepathy, strnpcinfo(3));
+ deletearray getvariableofnpc(.movepathx, strnpcinfo(3));
+ .@cnt = 0;
+
+ for (.@f = 0; .@f < getargcount(); .@f = .@f + 3)
+ {
+ set getvariableofnpc(.movepathcmd$[.@cnt], strnpcinfo(3)), getarg(.@f);
+ set getvariableofnpc(.movepathx[.@cnt], strnpcinfo(3)), getarg(.@f + 1);
+ set getvariableofnpc(.movepathy[.@cnt], strnpcinfo(3)), getarg(.@f + 2);
+ .@cnt ++;
+ }
+ //debugmes "array size: " + str(getarraysize(getvariableofnpc(.movepath, strnpcinfo(3))));
+ return;
+}
+
+function script domoveaction {
+ //debugmes "domoveaction: " + str(getvariableofnpc(.movepos, strnpcinfo(3)));
+ .@pos = getvariableofnpc(.movepos, strnpcinfo(3));
+ if (.@pos >= getarraysize(getvariableofnpc(.movepathx, strnpcinfo(3))) || .@pos < 0)
+ return;
+ //debugmes "walking";
+ .@cmd$ = getvariableofnpc(.movepathcmd$[.@pos], strnpcinfo(3));
+ //debugmes "cmd: " + .@cmd$;
+
+ if (.@cmd$ == "move")
+ {
+ npcwalkto getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)), getvariableofnpc(.movepathy[.@pos], strnpcinfo(3));
+ }
+ else if (.@cmd$ == "dir")
+ {
+ setnpcdir getvariableofnpc(.movepathx[.@pos], strnpcinfo(3));
+ return 2;
+ }
+ else if (.@cmd$ == "wait")
+ {
+ set getvariableofnpc(.waitticks, strnpcinfo(3)), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3));
+ }
+ else if (.@cmd$ == "emote")
+ {
+ unitemote getnpcid(), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3));
+ return 2;
+ }
+ else if (.@cmd$ == "class")
+ {
+ .class = getvariableofnpc(.movepathx[.@pos], strnpcinfo(3));
+ return 2;
+ }
+ else if (.@cmd$ == "warp")
+ {
+ movenpc strnpcinfo(3), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)), getvariableofnpc(.movepathy[.@pos], strnpcinfo(3));
+ }
+ else if (.@cmd$ == "goto")
+ {
+ set getvariableofnpc(.movepos, strnpcinfo(3)), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3));
+ return 0;
+ }
+ else if (.@cmd$ == "rmove")
+ {
+ getmapxy(.@mapName$, .@x, .@y, 1);
+ npcwalkto .@x + getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)), .@y + getvariableofnpc(.movepathy[.@pos], strnpcinfo(3));
+ }
+ else if (.@cmd$ == "speed")
+ {
+ .speed = getvariableofnpc(.movepathx[.@pos], strnpcinfo(3));
+ return 2;
+ }
+ else if (.@cmd$ == "sit")
+ {
+ npcsit;
+ }
+ else if (.@cmd$ == "stand")
+ {
+ npcstand;
+ }
+ return 1;
+}
+
+function script movetonextpos {
+ .@wait = getvariableofnpc(.waitticks, strnpcinfo(3));
+ if (.@wait > 0)
+ {
+ .@wait --;
+ //debugmes "wait";
+ set getvariableofnpc(.waitticks, strnpcinfo(3)), .@wait;
+ return;
+ }
+ .@true = 1;
+ while (.@true)
+ {
+ .@true = 0;
+ .@pos = getvariableofnpc(.movepos, strnpcinfo(3));
+ //debugmes "movetonextpos: " + str(.@pos);
+ .@res = domoveaction(.@pos);
+ if (.@res == 1 || .@res == 2)
+ {
+ .@pos++;
+ if (.@pos >= getarraysize(getvariableofnpc(.movepathx, strnpcinfo(3))))
+ .@pos = 0;
+ set getvariableofnpc(.movepos, strnpcinfo(3)), .@pos;
+ }
+ if (.@res == 0 || .@res == 2)
+ {
+ .@true = 1;
+ }
+ }
+ return;
+}
+
+function script initialmove {
+ set getvariableofnpc(.movepos, strnpcinfo(3)), 0;
+ set getvariableofnpc(.waitticks, strnpcinfo(3)), -1;
+ movetonextpos;
+ return;
+}
+
+function script getmovecmd {
+ .@pos = getvariableofnpc(.movepos, strnpcinfo(3));
+ if (.@pos >= getarraysize(getvariableofnpc(.movepathx, strnpcinfo(3))) || .@pos < 0)
+ return "";
+ return getvariableofnpc(.movepathcmd$[.@pos], strnpcinfo(3));
+}
+
+function script domovestep {
+ if (isunitwalking())
+ {
+ initnpctimer;
+ end;
+ }
+ movetonextpos;
+ initnpctimer;
+ end;
+}
diff --git a/npc/functions/npcmovegraph.txt b/npc/functions/npcmovegraph.txt
new file mode 100644
index 00000000..54e4e783
--- /dev/null
+++ b/npc/functions/npcmovegraph.txt
@@ -0,0 +1,485 @@
+// Evol functions.
+// Author:
+// Travolta
+// Description:
+// Moving npc utility functions (graph-based)
+// Variables:
+// none
+
+function script initmovegraph {
+ deletearray getvariableofnpc(.movegraphcmd$, strnpcinfo(3));
+ deletearray getvariableofnpc(.movegraphlabels$, strnpcinfo(3));
+ deletearray getvariableofnpc(.movegraphweight, strnpcinfo(3));
+ deletearray getvariableofnpc(.movegraphflags, strnpcinfo(3));
+ deletearray getvariableofnpc(.movepos_y1, strnpcinfo(3));
+ deletearray getvariableofnpc(.movepos_x1, strnpcinfo(3));
+ deletearray getvariableofnpc(.movepos_x2, strnpcinfo(3));
+ deletearray getvariableofnpc(.movepos_y2, strnpcinfo(3));
+ .@cnt = 0;
+
+ for (.@f = 0; .@f < getargcount();)
+ {
+ set getvariableofnpc(.movegraphlabels$[.@cnt], strnpcinfo(3)), getarg(.@f++);
+ set getvariableofnpc(.movepos_x1[.@cnt], strnpcinfo(3)), getarg(.@f++);
+ set getvariableofnpc(.movepos_y1[.@cnt], strnpcinfo(3)), getarg(.@f++);
+ if (!isstr(getarg(.@f, "label")))
+ {
+ set getvariableofnpc(.movepos_x2[.@cnt], strnpcinfo(3)), getarg(.@f++);
+ set getvariableofnpc(.movepos_y2[.@cnt], strnpcinfo(3)), getarg(.@f++);
+ }
+ .@cnt ++;
+ }
+ return;
+}
+
+function script findmovegraphlabel {
+ if (!getargcount())
+ {
+ consolemes(CONSOLEMES_DEBUG, "findmovegraphlabel: no argument");
+ return -1;
+ }
+ if (!isstr(getarg(0)))
+ {
+ consolemes(CONSOLEMES_DEBUG, "findmovegraphlabel: need string argument");
+ return -1;
+ }
+
+ .@arg$ = getarg(0);
+ for (.@i = 0; .@i < getarraysize(getvariableofnpc(.movegraphlabels$, strnpcinfo(3))); .@i++)
+ {
+ if (getvariableofnpc(.movegraphlabels$[.@i], strnpcinfo(3)) == .@arg$)
+ return .@i;
+ }
+
+ npcdebug "findmovegraphlabel: label not found: " + getarg(0);
+ return -1;
+}
+
+/* setmovegraphcmd(fromPositionLabel,toPositionLabel[,moveChanceWeight[,moveFlags]],postCommand, ...);
+ * This function manipulates NPC moving graph. Before calling it, make sure
+ * `initmovegraph' was called. The function accepts 3-5 parameters (many times):
+ * fromPositionLabel, toPositionLabel -- starting and ending position of NPC move
+ * moveChanceWeight -- positive integer, represents the chance of moving in given direction. (optional)
+ * moveFlags -- if .mg_flags & moveFlags != 0, move is possible. (optional)
+ * postCommand -- either "moveon" (start moving to next location straight after arriving from
+ * fromPositionLabel to toPositionLabel) or a semicolon-separated set of commands
+ * ("wait 3", "emote 5" etc, see `execmovecmd') that will be executed after arrival.
+ * The commands don't have to end with ";moveon", it's executed in the end by default.
+ */
+function script setmovegraphcmd {
+ .@size = getarraysize(getvariableofnpc(.movepos_x1, strnpcinfo(3)));
+
+ for (.@f = 0; .@f < getargcount();)
+ {
+ .@from = findmovegraphlabel(getarg(.@f++));
+ .@to = findmovegraphlabel(getarg(.@f++));
+ .@weight = 1;
+ if (!isstr(getarg(.@f)))
+ .@weight = getarg(.@f++);
+ .@flags = 0xffff;
+ if (!isstr(getarg(.@f)))
+ .@flags = getarg(.@f++);
+ .@cmd$ = getarg(.@f++);
+ .@index = .@from * .@size + .@to; // emulation of 2d array
+ set getvariableofnpc(.movegraphcmd$[.@index], strnpcinfo(3)), .@cmd$;
+ set getvariableofnpc(.movegraphweight[.@index], strnpcinfo(3)), .@weight;
+ set getvariableofnpc(.movegraphflags[.@index], strnpcinfo(3)), .@flags;
+ }
+ return;
+}
+
+function script execmovecmd {
+
+ explode(.@cmd$, getarg(0), " ");
+
+ if (.@cmd$[0] == "moveon")
+ {
+ return 0;
+ }
+ else if (.@cmd$[0] == "dir")
+ {
+ .dir = atoi(.@cmd$[1]);
+ }
+ else if (.@cmd$[0] == "sit")
+ {
+ npcsit;
+ }
+ else if (.@cmd$[0] == "stand")
+ {
+ npcstand;
+ }
+ else if (.@cmd$[0] == "wait")
+ {
+ set getvariableofnpc(.waitticks, strnpcinfo(3)), atoi(.@cmd$[1]);
+ return 1;
+ }
+ else if (.@cmd$[0] == "emote")
+ {
+ unitemote getnpcid(), atoi(.@cmd$[1]);
+ }
+ else if (.@cmd$[0] == "class")
+ {
+ .class = atoi(.@cmd$[1]);
+ }
+ else if (.@cmd$[0] == "warp")
+ {
+ .@pos = -1;
+ .@map$ = "";
+ .@pos_idx = 1;
+ if (getarraysize(.@cmd$) == 3)
+ {
+ .@map$ = .@cmd$[1];
+ .@pos_idx = 2;
+ }
+ .@pos = findmovegraphlabel(.@cmd$[.@pos_idx]);
+ if (.@pos != -1)
+ {
+ .@x = getvariableofnpc(.movepos_x1[.@pos], strnpcinfo(3));
+ .@y = getvariableofnpc(.movepos_y1[.@pos], strnpcinfo(3));
+ if (getstrlen(.@map$) > 0)
+ unitwarp getnpcid(), .@map$, .@x, .@y;
+ else
+ movenpc strnpcinfo(3), .@x, .@y;
+ set getvariableofnpc(.movepos, strnpcinfo(3)), .@pos;
+ }
+ else
+ {
+ consolemes(CONSOLEMES_DEBUG, "execmovecmd: unknown WARP destination label: " + .@cmd$[1]);
+ }
+ }
+ else if (.@cmd$[0] == "call")
+ {
+ switch (getarraysize(.@cmd$))
+ {
+ case 1:
+ consolemes(CONSOLEMES_DEBUG, "execmovecmd: CALL command needs some parameters");
+ return 0;
+ case 2:
+ return callfunc(.@cmd$[1]);
+ break;
+ case 3:
+ return callfunc(.@cmd$[1], .@cmd$[2]);
+ case 4:
+ default:
+ return callfunc(.@cmd$[1], .@cmd$[2], .@cmd$[3]);
+ }
+ }
+ else if (.@cmd$[0] == "speed")
+ {
+ .speed = atoi(.@cmd$[1]);
+ }
+ else if (.@cmd$[0] == "say")
+ {
+ deletearray .@cmd$[0], 1;
+ npctalk implode(.@cmd$, " ");
+ }
+ else if (.@cmd$[0] == "debugmes")
+ {
+ deletearray .@cmd$[0], 1;
+ consolemes(CONSOLEMES_DEBUG, implode(.@cmd$, " "));
+ }
+ else if (.@cmd$[0] == "flags")
+ {
+ set getvariableofnpc(.mg_flags, strnpcinfo(3)), axtoi(.@cmd$[1]);
+ }
+ else if (.@cmd$[0] == "flags_0")
+ {
+ .@flags = getvariableofnpc(.mg_flags, strnpcinfo(3));
+ .@flags &= ~axtoi(.@cmd$[1]);
+ set getvariableofnpc(.mg_flags, strnpcinfo(3)), .@flags;
+ }
+ else if (.@cmd$[0] == "flags_1")
+ {
+ .@flags = getvariableofnpc(.mg_flags, strnpcinfo(3));
+ .@flags |= axtoi(.@cmd$[1]);
+ set getvariableofnpc(.mg_flags, strnpcinfo(3)), .@flags;
+ }
+ else
+ {
+ consolemes(CONSOLEMES_DEBUG, "Unknown move graph cmd: " + .@cmd$[0]);
+ }
+ return 0;
+}
+
+function script getnextmovecmd {
+ .@cmds$ = getvariableofnpc(.nextcmd$, strnpcinfo(3));
+ .@firstCmd$ = .@cmds$;
+ .@restCmd$ = "moveon";
+ .@index = strpos(.@cmds$, ";");
+ if (.@index >= 0)
+ {
+ .@firstCmd$ = substr(.@cmds$, 0, .@index - 1);
+ .@restCmd$ = substr(.@cmds$, .@index + 1, getstrlen(.@cmds$) - 1);
+ }
+ // npcdebug "firstCmd = " + .@firstCmd$ + " restCmd = " + .@restCmd$;
+ set getvariableofnpc(.nextcmd$, strnpcinfo(3)), .@restCmd$;
+ return strip(.@firstCmd$);
+}
+
+// getrandompoint(x1,y1,x2,y2)
+// -- Get a random walkable point within a map rectangle
+// x1, y1 -- top-left corner of rectangle
+// x2, y2 -- bottom-right corner of rectangle
+// Returns 0 on success and -1 on error;
+// Since we cannot return multiple values, the random
+// coordinates are stored in NPC variables .move__rand_x, .move__rand_y
+function script getrandompoint {
+ if (getargcount() < 4)
+ {
+ consolemes(CONSOLEMES_DEBUG, "error: getrandompoint(x1, y1, x2, y2) takes 4 arguments");
+ return -1;
+ }
+
+ .@max_pokes = 10;
+ .@x1 = getarg(0);
+ .@y1 = getarg(1);
+ .@x2 = getarg(2);
+ .@y2 = getarg(3);
+ .@rx = -1; .@ry = -1;
+
+ getmapxy(.@map$, .@cx, .@cy, 1); // npc location
+
+ // let's try max_pokes random cells
+ for (.@poke = 0; .@poke < .@max_pokes; .@poke++)
+ {
+ .@rx = rand(.@x1, .@x2);
+ .@ry = rand(.@y1, .@y2);
+ if (checknpccell(.@map$, .@rx, .@ry, cell_chkpass))
+ goto L_Found;
+ }
+
+ // we check each cell from random middle point to the end
+ for (;.@rx <= .@x2; .@rx++)
+ {
+ for (;.@ry <= .@y2; .@ry++)
+ if (checknpccell(.@map$, .@rx, .@ry, cell_chkpass))
+ goto L_Found;
+ .@ry = .@y1;
+ }
+
+ // we check the rectangle from beginning to end
+ for (.@rx = .@x1; .@rx <= .@x2; .@rx++)
+ for (.@ry = .@y1; .@ry <= .@y2; .@ry++)
+ if (checknpccell(.@map$, .@rx, .@ry, cell_chkpass))
+ goto L_Found;
+
+ // finally, if we don't find anything
+ consolemes(CONSOLEMES_DEBUG, "error: getrandompoint: cannot find walkable cell in rectangle [(" + .@x1 + "," + .@y1 + ") , (" + .@x2 + "," + .@y2 + ")]");
+ return -1;
+
+L_Found:
+ set getvariableofnpc(.move__rand_x, strnpcinfo(3)), .@rx;
+ set getvariableofnpc(.move__rand_y, strnpcinfo(3)), .@ry;
+ return 0;
+}
+
+// wrapper function for npcwalkto. It can accept 4 parameters.
+// If #3 and #4 params are set, the walkto location is chosen
+// from rectangle (x1,y1,x2,y2).
+// It sets the npc variables .move_target_x, .move_target_y
+// that are used to resume NPC walking
+// Returns 1 if walking is possible, 0 otherwise;
+function script mg_npcwalkto {
+ if (getargcount() < 2)
+ {
+ consolemes(CONSOLEMES_DEBUG, "usage: mg_npcwalkto(x1,y1[,x2,y2])");
+ return -1;
+ }
+
+ .@x = getarg(0);
+ .@y = getarg(1);
+ .@x2 = getarg(2);
+ .@y2 = getarg(3);
+
+ if (getargcount() >= 4 && .@x2 > 0 && .@y2 > 0)
+ if (!getrandompoint(.@x, .@y, .@x2, .@y2))
+ {
+ .@x = getvariableofnpc(.move__rand_x, strnpcinfo(3));
+ .@y = getvariableofnpc(.move__rand_y, strnpcinfo(3));
+ }
+ else
+ return 0;
+
+ if (npcwalkto(.@x, .@y))
+ {
+ set getvariableofnpc(.move_target_x, strnpcinfo(3)), .@x;
+ set getvariableofnpc(.move_target_y, strnpcinfo(3)), .@y;
+ return 1;
+ }
+ return 0;
+}
+
+function script movetonextpoint {
+ .@wait = getvariableofnpc(.waitticks, strnpcinfo(3));
+ if (.@wait > 0)
+ {
+ .@wait--;
+ set getvariableofnpc(.waitticks, strnpcinfo(3)), .@wait;
+ return;
+ }
+
+ .@nextcmd$ = "";
+ while (.@nextcmd$ != "moveon")
+ {
+ .@nextcmd$ = getnextmovecmd();
+ npcdebug " " + .@nextcmd$;
+ if (execmovecmd(.@nextcmd$))
+ return;
+ }
+
+ // choose a random path from all possible paths
+ .@size = getarraysize(getvariableofnpc(.movepos_x1, strnpcinfo(3)));
+ .@pos = getvariableofnpc(.movepos, strnpcinfo(3));
+ .@curr_flags = getvariableofnpc(.mg_flags, strnpcinfo(3));
+ .@cur = 0;
+ .@weight_sum = 0;
+ // .@dbg$ = getvariableofnpc(.movegraphlabels$[.@pos], strnpcinfo(3)) + ": ";
+
+ for (.@i = 0; .@i < .@size; .@i++)
+ {
+ .@index = .@pos * .@size + .@i;
+ .@cmd$ = getvariableofnpc(.movegraphcmd$[.@index], strnpcinfo(3));
+ .@flags = getvariableofnpc(.movegraphflags[.@index], strnpcinfo(3));
+ if (.@cmd$ != "" &&
+ .@curr_flags & .@flags)
+ {
+ .@nextpos[.@cur] = .@i;
+ .@weights[.@cur] = getvariableofnpc(.movegraphweight[.@index], strnpcinfo(3));
+ // .@dbg$ += getvariableofnpc(.movegraphlabels$[.@i], strnpcinfo(3)) + "=" + .@weights[.@cur] + " ";
+ .@weight_sum += .@weights[.@cur];
+ .@cur++;
+ }
+ }
+ // npcdebug .@dbg$;
+
+ if (!.@weight_sum)
+ {
+ npcdebug("error: cannot pick next walk point. flags=" +
+ getvariableofnpc(.mg_flags, strnpcinfo(3)));
+ return;
+ }
+
+ .@pick_tries = 0;
+L_TryPick:
+ // pick a random number based on weight_sum
+ .@rnd = rand(.@weight_sum);
+ .@k = -1; .@weight_sum = 0;
+ while (.@rnd >= .@weight_sum)
+ {
+ .@k++;
+ .@weight_sum += .@weights[.@k];
+ }
+
+ .@next_idx = .@nextpos[.@k];
+ .@next_x1 = getvariableofnpc(.movepos_x1[.@next_idx], strnpcinfo(3));
+ .@next_y1 = getvariableofnpc(.movepos_y1[.@next_idx], strnpcinfo(3));
+ .@next_x2 = getvariableofnpc(.movepos_x2[.@next_idx], strnpcinfo(3));
+ .@next_y2 = getvariableofnpc(.movepos_y2[.@next_idx], strnpcinfo(3));
+
+ if (!mg_npcwalkto(.@next_x1, .@next_y1, .@next_x2, .@next_y2))
+ {
+ if (.@pick_tries < 10)
+ {
+ .@pick_tries++;
+ goto L_TryPick;
+ }
+
+ // move to a nearby position
+ .@x1 = getvariableofnpc(.movepos_x1[.@pos], strnpcinfo(3));
+ .@y1 = getvariableofnpc(.movepos_y1[.@pos], strnpcinfo(3));
+ .@x2 = getvariableofnpc(.movepos_x2[.@pos], strnpcinfo(3));
+ .@y2 = getvariableofnpc(.movepos_y2[.@pos], strnpcinfo(3));
+ mg_npcwalkto(.@x1, .@y1, .@x2, .@y2);
+ set getvariableofnpc(.nextcmd$, strnpcinfo(3)), "wait 1";
+
+ return;
+ }
+
+ if (getvariableofnpc(.debug, strnpcinfo(3)))
+ {
+ getmapxy(.@map$, .@cx, .@cy, 1);
+ .@dist = distance(.@cx, .@cy, .@next_x1, .@next_y1);
+ npcdebug("moving to " + getvariableofnpc(.movegraphlabels$[.@next_idx], strnpcinfo(3)) +
+ " ("+ getvariableofnpc(.move_target_x, strnpcinfo(3)) +
+ "," + getvariableofnpc(.move_target_y, strnpcinfo(3)) +
+ ") [distance=" + .@dist +
+ "] flags=" + getvariableofnpc(.mg_flags, strnpcinfo(3)));
+ }
+
+ .@nextcmd$ = getvariableofnpc(.movegraphcmd$[.@pos * .@size + .@next_idx], strnpcinfo(3));
+ set getvariableofnpc(.nextcmd$, strnpcinfo(3)), .@nextcmd$;
+ set getvariableofnpc(.movepos, strnpcinfo(3)), .@next_idx;
+ return;
+}
+
+// initial actions for npc when using move graphs.
+// function can accept 2 arguments:
+// 1: action sequence, for example "speed 200; dir 4". Default is "moveon"
+// 2: start point label. Default is #0 from move graph labels
+function script firstmove {
+ .@nextcmd$ = getarg(0, "moveon");
+ .@initpos = findmovegraphlabel(getarg(1, ""));
+ if (.@initpos < 0) .@initpos = 0;
+
+ set getvariableofnpc(.movepos, strnpcinfo(3)), .@initpos;
+ movenpc strnpcinfo(3), getvariableofnpc(.movepos_x1[.@initpos], strnpcinfo(3)),
+ getvariableofnpc(.movepos_y1[.@initpos], strnpcinfo(3));
+ set getvariableofnpc(.nextcmd$, strnpcinfo(3)), .@nextcmd$;
+ set getvariableofnpc(.waitticks, strnpcinfo(3)), -1;
+ set getvariableofnpc(.mg_flags, strnpcinfo(3)), 0xffff;
+ movetonextpoint;
+ return;
+}
+
+function script npc_pausemove {
+ stopnpctimer;
+ .@move_after = 0;
+
+ if (isunitwalking())
+ {
+ .@move_after = 1;
+ npcwalkto .x, .y;
+ npcstop;
+ }
+ set getvariableofnpc(.move_after_pause, strnpcinfo(3)), .@move_after;
+
+ return 0;
+}
+
+function script npc_resumemove {
+ startnpctimer;
+
+ if (getvariableofnpc(.move_after_pause, strnpcinfo(3)))
+ {
+ .@x = getvariableofnpc(.move_target_x, strnpcinfo(3));
+ .@y = getvariableofnpc(.move_target_y, strnpcinfo(3));
+ npcwalkto .@x, .@y;
+ }
+
+ return 0;
+}
+
+// npc_turntoxy(x,y)
+// turn npc toward an object at position (x,y)
+function script npc_turntoxy {
+ .@target_x = getarg(0);
+ .@target_y = getarg(1);
+ .@dx = abs(.@target_x - .x);
+ .@dy = abs(.@target_y - .y);
+
+ if (.@dx > .@dy)
+ .dir = .@target_x >= .x ? 6 : 2;
+ else
+ .dir = .@target_y >= .y ? 0 : 4;
+
+ return 0;
+}
+
+function script dographmovestep {
+ if (!isunitwalking())
+ {
+ movetonextpoint;
+ }
+ initnpctimer;
+ end;
+}
diff --git a/npc/functions/openbook.txt b/npc/functions/openbook.txt
new file mode 100644
index 00000000..cb1a0b11
--- /dev/null
+++ b/npc/functions/openbook.txt
@@ -0,0 +1,34 @@
+// Evol functions.
+// Author:
+// Reid
+// Description:
+// Narrator dialogue to show the selected book.
+
+function script openbook {
+ .@book_name$ = getarg(0, getvariableofnpc(.book_name$, strnpcinfo(0)));
+
+ narrator(S_LAST_NEXT,
+ l("You open a book named \"%s\".", .@book_name$),
+ l("Do you want to read it?"));
+
+ return (select("Yes.", "No.") == 1);
+}
+
+function script openbookshelf {
+ .@book_name$ = getarg(0, getvariableofnpc(.book_name$, strnpcinfo(0)));
+
+ narrator(S_LAST_NEXT,
+ l("You see a dust covered book on the shelf..."),
+ l("The name of the book is \"%s\".", .@book_name$),
+ l("Do you want to read it?"));
+
+ return (select("Yes.", "No.") == 1);
+}
+
+function script openoldbook {
+ narrator S_LAST_NEXT,
+ l("You open the book, but it looks like the sea water and time damaged it severely. Some pages are not readable anymore. Some others are simply missing."),
+ l("The old book seems to tell about the legend of Aemil. Would you like to read it?");
+
+ return (select("Yes.", "No.") == 1);
+}
diff --git a/npc/functions/permissions.txt b/npc/functions/permissions.txt
new file mode 100644
index 00000000..96e69fde
--- /dev/null
+++ b/npc/functions/permissions.txt
@@ -0,0 +1,35 @@
+// Evol scripts.
+// Author:
+// gumi
+// Description:
+// checks player permissions
+// ** admins are implicitly everything
+
+// administrator
+function script is_admin {
+ return has_permission(PERM_USE_ALL_COMMANDS, getarg(0, getcharid(CHAR_ID_ACCOUNT)));
+}
+
+// any staff member
+function script is_trusted {
+ return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) ||
+ has_permission("show_client_version", getarg(0, getcharid(CHAR_ID_ACCOUNT)));
+}
+
+// developer
+function script is_dev {
+ return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) ||
+ has_permission(PERM_RECEIVE_REQUESTS, getarg(0, getcharid(CHAR_ID_ACCOUNT)));
+}
+
+// event coordinator
+function script is_evtc {
+ return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) ||
+ can_use_command("@monster", getarg(0, getcharid(CHAR_ID_ACCOUNT)));
+}
+
+// game master
+function script is_gm {
+ return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) ||
+ can_use_command("@jail", getarg(0, getcharid(CHAR_ID_ACCOUNT)));
+}
diff --git a/npc/functions/player-cache.txt b/npc/functions/player-cache.txt
new file mode 100644
index 00000000..f134f953
--- /dev/null
+++ b/npc/functions/player-cache.txt
@@ -0,0 +1,501 @@
+// Player cache system
+//
+// Holds a cache of online players in-memory even after logout. This greatly
+// reduces the need to query the SQL database for data that is frequently
+// accessed.
+//
+// NOTE: This NPC uses the new public/private function call system to avoid
+// polluting the global function namespace
+//
+// Example usage:
+// .@account_id = "playerCache"::name2account("Reid");
+//
+
+- script playerCache FAKE_NPC,{
+ /**
+ * "playerCache"::name2account("char name") => account id
+ *
+ * Searches through the player cache to convert a char name to a account ID.
+ * If the player is not found, checks the SQL table. If the player doesn't
+ * exist, returns false.
+ *
+ * @param 0 - the char name to search
+ * @return the account id of the char
+ */
+ public function name2account {
+ if (getarg(0) == "") {
+ return false;
+ }
+
+ if (.@acc = getcharid(CHAR_ID_ACCOUNT, getarg(0))) {
+ // player is currently online
+ return .@acc;
+ }
+
+ if (.@acc = htget(.name_to_account, getarg(0), 0)) {
+ // player found in the hash table
+ return .@acc;
+ }
+
+ // player still not found: now we try SQL
+ .@name$ = escape_sql(getarg(0));
+
+ if (SERVER_USES_VAULT) {
+ query_sql(sprintf("SELECT c.account_id, c.char_id, r.value "
+ "FROM `char` c "
+ "JOIN `global_acc_reg_num_db` r ON r.account_id = c.account_id "
+ "WHERE r.key = '##VAULT' AND r.index = 0 AND c.name = '%s' "
+ "LIMIT 1;", .@name$),
+ .@acc, .@char, .@vault);
+
+ if (.@vault > 0) {
+ .vault_to_account[.@vault] = .@acc;
+ .account_to_vault[.@acc] = .@vault;
+ }
+ } else {
+ query_sql(sprintf("SELECT account_id, char_id FROM `char` WHERE `name`='%s' LIMIT 1;", .@name$), .@acc, .@char);
+ }
+
+ if (.@acc > 0) {
+ // player found: add to our cache
+ htput(.name_to_account, getarg(0), .@acc);
+ .account_to_name$[.@acc] = getarg(0);
+ htput(.name_to_char, getarg(0), .@char);
+ .char_to_name$[.@char] = getarg(0);
+
+ return .@acc;
+ }
+
+ // player doesn't exist
+ return false;
+ }
+
+ /**
+ * "playerCache"::name2char("char name") => char id
+ *
+ * Searches through the player cache to convert a char name to a char ID.
+ * If the player is not found, checks the SQL table. If the player doesn't
+ * exist, returns false.
+ *
+ * @param 0 - the char name to search
+ * @return the char id of the char
+ */
+ public function name2char {
+ if ((.@acc = name2account(getarg(0))) != 0) {
+ return htget(.name_to_char, getarg(0), false);
+ }
+
+ return false;
+ }
+
+ /**
+ * "playerCache"::char2account(char id) => account id
+ *
+ * Searches through the player cache to convert a char ID to an account ID.
+ * If the player is not found, checks the SQL table. If the player doesn't
+ * exist, returns false.
+ *
+ * @param 0 - the char ID to search
+ * @return the account id of the char
+ */
+ public function char2account {
+ if (getarg(0) == 0) {
+ return false;
+ }
+
+ .@name$ = .char_to_name$[getarg(0)];
+
+ if (.@name$ != "") {
+ if (.@acc = getcharid(CHAR_ID_ACCOUNT, .@name$)) {
+ // player is currently online
+ return .@acc;
+ }
+
+ if (.@acc = htget(.name_to_account, .@name$, 0)) {
+ // player found in the hash table
+ return .@acc;
+ }
+ }
+
+ // player still not found: now we try SQL
+ if (SERVER_USES_VAULT) {
+ query_sql(sprintf("SELECT c.account_id, c.name, r.value "
+ "FROM `char` c "
+ "JOIN `global_acc_reg_num_db` r ON r.account_id = c.account_id "
+ "WHERE r.key = '##VAULT' AND r.index = 0 AND c.char_id = '%d' "
+ "LIMIT 1;", getarg(0)),
+ .@acc, .@name$, .@vault);
+
+ if (.@vault > 0) {
+ .vault_to_account[.@vault] = .@acc;
+ .account_to_vault[.@acc] = .@vault;
+ }
+ } else {
+ query_sql(sprintf("SELECT account_id, name FROM `char` WHERE `char_id`='%d' LIMIT 1;", getarg(0)), .@acc, .@name$);
+ }
+
+ if (.@acc > 0) {
+ // player found: add to our cache
+ htput(.name_to_account, .@name$, .@acc);
+ .account_to_name$[.@acc] = .@name$;
+ htput(.name_to_char, .@name$, getarg(0));
+ .char_to_name$[getarg(0)] = .@name$;
+
+ return .@acc;
+ }
+
+ // player doesn't exist
+ return false;
+ }
+
+ /**
+ * "playerCache"::account2char(account id) => char id
+ *
+ * Searches through the player cache to convert an account ID into a
+ * char ID. If the player is not found, returns false.
+ *
+ * NOTE: this is a weak reference; an account ID does not uniquely identify
+ * a character
+ *
+ * @param 0 - the account ID to search for
+ * @return the char ID of the char
+ */
+ public function account2char {
+ if (getarg(0) == 0) {
+ return false;
+ }
+
+ if ((.@name$ = strcharinfo(PC_NAME, "", getarg(0))) != "") {
+ // player is online
+ return getcharid(CHAR_ID_CHAR, .@name$);
+ } else if ((.@name$ = .account_to_name$[getarg(0)]) != "") {
+ // found in our cache
+ return htget(.name_to_char, .@name$, false);
+ }
+
+ // player still not found: now we try SQL
+ if (SERVER_USES_VAULT) {
+ query_sql(sprintf("SELECT c.char_id, c.name, r.value "
+ "FROM `char` c "
+ "JOIN `global_acc_reg_num_db` r ON r.account_id = c.account_id "
+ "WHERE r.key = '##VAULT' AND r.index = 0 AND c.account_id = '%d' "
+ "ORDER BY c.last_login DESC LIMIT 1;", getarg(0)),
+ .@char, .@name$, .@vault);
+
+ if (.@vault > 0) {
+ .vault_to_account[.@vault] = getarg(0);
+ .account_to_vault[getarg(0)] = .@vault;
+ }
+ } else {
+ query_sql(sprintf("SELECT char_id, name FROM `char` WHERE account_id='%d' ORDER BY last_login DESC LIMIT 1;", getarg(0)), .@char, .@name$);
+ }
+
+ if (.@char > 0) {
+ // player found: add to our cache
+ htput(.name_to_account, .@name$, getarg(0));
+ .account_to_name$[getarg(0)] = .@name$;
+ htput(.name_to_char, .@name$, .@char);
+ .char_to_name$[.@char] = .@name$;
+
+ return .@char;
+ }
+
+ // not found
+ return false;
+ }
+
+ /**
+ * "playerCache"::account2name(account id) => char name
+ *
+ * Searches through the player cache to convert an account ID into a
+ * char name. If the account is not found, returns an empty string.
+ *
+ * NOTE: this is a weak reference; an account ID does not uniquely identify
+ * a character
+ *
+ * @param 0 - the account ID to search for
+ * @return the name of the char
+ */
+ public function account2name {
+ if ((.@char = account2char(getarg(0))) != false) {
+ return .char_to_name$[.@char];
+ }
+
+ return "";
+ }
+
+ /**
+ * "playerCache"::char2name(char id) => char name
+ *
+ * Searches through the player cache to convert a char ID to a char name.
+ * If the player is not found, checks the SQL table. If the player doesn't
+ * exist, returns an empty string.
+ *
+ * @param 0 - the char ID to search
+ * @return the name of the char
+ */
+ public function char2name {
+ if ((.@acc = char2account(getarg(0))) != 0) {
+ return .account_to_name$[.@acc];
+ }
+
+ // player not found
+ return "";
+ }
+
+ /**
+ * "playerCache"::vault2account(vault id) => account id
+ *
+ * Searches through the player cache to convert a Vault account ID into a
+ * game account ID. If the account is not found, returns false
+ *
+ * NOTE: this is a weak reference; a Vault ID does not uniquely identify
+ * a game account
+ *
+ * @param 0 - the Vault ID to search for
+ * @return the account id of the char
+ */
+ public function vault2account {
+ if (getarg(0) == 0) {
+ return false;
+ }
+
+ if (!SERVER_USES_VAULT) {
+ return getarg(0);
+ } else if (.@acc = .vault_to_account[getarg(0)]) {
+ // found in the cache
+ return .@acc;
+ }
+
+ // player still not found: now we try SQL
+ query_sql(sprintf("SELECT c.account_id, c.char_id, c.name "
+ "FROM `char` c "
+ "JOIN `global_acc_reg_num_db` r ON r.account_id = c.account_id "
+ "WHERE r.key = '##VAULT' AND r.index = 0 AND r.value = %d "
+ "ORDER BY c.`last_login` DESC LIMIT 1;", getarg(0)),
+ .@acc, .@char, .@name$);
+
+ if (.@char > 0) {
+ // player found: add to our cache
+ htput(.name_to_account, .@name$, .@acc);
+ .account_to_name$[.@acc] = .@name$;
+ htput(.name_to_char, .@name$, .@char);
+ .char_to_name$[.@char] = .@name$;
+ .vault_to_account[getarg(0)] = .@acc;
+ .account_to_vault[.@acc] = getarg(0);
+
+ return .@acc;
+ }
+
+ return false;
+ }
+
+ /**
+ * "playerCache"::vault2char(vault id) => char id
+ *
+ * Searches through the player cache to convert a Vault account ID into a
+ * char id. If the player is not found, returns false
+ *
+ * NOTE: this is a weak reference; a Vault ID does not uniquely identify
+ * a character
+ *
+ * @param 0 - the Vault ID to search for
+ * @return the char id
+ */
+ public function vault2char {
+ if ((.@acc = vault2account(getarg(0))) != 0) {
+ return account2char(.@acc);
+ }
+
+ // player not found
+ return false;
+ }
+
+ /**
+ * "playerCache"::vault2name(vault id) => account id
+ *
+ * Searches through the player cache to convert a Vault account ID into a
+ * char name. If the player is not found, returns an empty string
+ *
+ * NOTE: this is a weak reference; a Vault ID does not uniquely identify
+ * a character
+ *
+ * @param 0 - the Vault ID to search for
+ * @return the name of the char
+ */
+ public function vault2name {
+ if ((.@acc = vault2account(getarg(0))) != 0) {
+ return account2name(.@acc);
+ }
+
+ // player not found
+ return "";
+ }
+
+ /**
+ * "playerCache"::account2vault(account id) => vault id
+ *
+ * Searches through the player cache to convert a game account ID into a
+ * Vault account ID. If the account is not found, returns false
+ *
+ * @param 0 - the account ID to search for
+ * @return the Vault ID associated with the account
+ */
+ public function account2vault {
+ if (!SERVER_USES_VAULT) {
+ return getarg(0);
+ }
+
+ account2char(getarg(0)); // will fetch vault id
+ return .account_to_vault[getarg(0)];
+ }
+
+ /**
+ * "playerCache"::name2vault(char name) => vault id
+ *
+ * Searches through the player cache to convert a character name into a
+ * Vault account ID. If the account is not found, returns false
+ *
+ * @param 0 - the char name to search for
+ * @return the Vault ID associated with the account
+ */
+ public function name2vault {
+ return account2vault(name2account(getarg(0)));
+ }
+
+ /**
+ * "playerCache"::char2vault(char id) => vault id
+ *
+ * Searches through the player cache to convert a char id into a
+ * Vault account ID. If the account is not found, returns false
+ *
+ * @param 0 - the char id to search for
+ * @return the Vault ID associated with the account
+ */
+ public function char2vault {
+ return account2vault(char2account(getarg(0)));
+ }
+
+ /**
+ * Registers a public local function that will be called when the char name
+ * associated with an account changes. The previous account ID will be
+ * passed as first argument to the provided function.
+ *
+ * @param 0 - the public local function
+ */
+ public function addNameHandler {
+ return addEventListener(.name_handlers, getarg(0));
+ }
+
+ /**
+ * Registers a public local function that will be called when the account
+ * associated with a Vault account changes. The previous account id will be
+ * passed as first argument to the provided function and the previous
+ * char name will be passed as second argument.
+ *
+ * @param 0 - the public local function
+ */
+ public function addVaultHandler {
+ return addEventListener(.vault_handlers, getarg(0));
+ }
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * updates the char name cache and fires event handlers when the name
+ * associated with an account changes (such as when switching char)
+ */
+ private function updateName {
+ // get the cached name:
+ .@old$ = .account_to_name$[playerattached()];
+
+ // now update the cache:
+ htput(.name_to_account, strcharinfo(PC_NAME), playerattached());
+ .account_to_name$[playerattached()] = strcharinfo(PC_NAME);
+ htput(.name_to_char, strcharinfo(PC_NAME), getcharid(CHAR_ID_CHAR));
+ .char_to_name$[getcharid(CHAR_ID_CHAR)] = strcharinfo(PC_NAME);
+
+ if (.@old$ != "" && .@old$ != .account_to_name$[playerattached()]) {
+ // fire event handlers
+ dispatchEvent(.name_handlers, .@old$);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * updates the Vault account cache and fires event handlers when the account
+ * associated with a Vault account changes (different game account on same
+ * Vault account)
+ */
+ private function updateVault {
+ // get the cached id:
+ .@old = .vault_to_account[getvaultid()];
+ .@old$ = .account_to_name$[.@old];
+
+ // now update the cache:
+ .vault_to_account[getvaultid()] = playerattached();
+ .account_to_vault[playerattached()] = getvaultid();
+
+ if (.@old > 0 && .@old != .vault_to_account[getvaultid()]) {
+ // fire event handlers
+ dispatchEvent(.vault_handlers, .@old, .@old$);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * adds/updates the player to the player cache
+ */
+ private function updateCache {
+ updateName();
+
+ if (SERVER_USES_VAULT) {
+ updateVault();
+ }
+
+ return;
+ }
+
+ /**
+ * force-add all online players to the cache (used on init and reload)
+ */
+ private function forceCache {
+ .@count = getunits(BL_PC, .@units, false);
+
+ for (.@i = 0; .@i < .@count; ++.@i) {
+ attachrid(.@units[.@i]);
+ updateCache();
+ detachrid();
+ }
+
+ return;
+ }
+
+OnPCLoginEvent:
+ updateCache();
+ end;
+
+OnInit:
+ .name_to_account = htnew(); // Map<char name, account id>
+ .account_to_name$[0] = ""; // sparse Array<char name> indexed by account id
+ .name_to_char = htnew(); // Map<char name, char id>
+ .char_to_name$[0] = ""; // sparse Array<char name> indexed by char id
+
+ if (SERVER_USES_VAULT) {
+ .vault_to_account[0] = 0; // sparse Array<vault id> indexed by account id
+ .account_to_vault[0] = 0; // sparse Array<account id> indexed by vault id
+ }
+
+ // event handlers:
+ .vault_handlers = htnew();
+ .name_handlers = htnew();
+
+ // reloadscript handler:
+ forceCache();
+}
diff --git a/npc/functions/quest-debug/000-ShipQuests_Julia.txt b/npc/functions/quest-debug/000-ShipQuests_Julia.txt
new file mode 100644
index 00000000..e4e0ec2c
--- /dev/null
+++ b/npc/functions/quest-debug/000-ShipQuests_Julia.txt
@@ -0,0 +1,37 @@
+// Julia quest debug
+// Author:
+// gumi
+
+function script QuestDebug0 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Julia";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Julia));
+ mes "---";
+ mes l("Related quests:");
+ mes "ShipQuests_Nard: " + getq(ShipQuests_Nard);
+ mes "ShipQuests_ChefGado: " + getq(ShipQuests_ChefGado);
+ mes "General_Narrator: " + getq(General_Narrator);
+ next;
+
+ GenericQuestDebug ShipQuests_Julia,
+ menuimage("actions/manage", l("Debug Nard quest")), -1,
+ menuimage("actions/manage", l("Debug Gado quest")), -2,
+ menuimage("actions/manage", l("Debug Narrator")), -3,
+ l("Does not have the quest"), 0,
+ l("Got the quest"), 1,
+ l("Completed"), 2;
+
+ switch (@menuret)
+ {
+ case -1: callfunc "QuestDebug4"; break;
+ case -2: callfunc "QuestDebug17"; break;
+ case -3: callfunc "QuestDebug28"; break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/001-ShipQuests_Arpan.txt b/npc/functions/quest-debug/001-ShipQuests_Arpan.txt
new file mode 100644
index 00000000..26c49646
--- /dev/null
+++ b/npc/functions/quest-debug/001-ShipQuests_Arpan.txt
@@ -0,0 +1,27 @@
+// Arpan quest debug
+// Author:
+// gumi
+
+function script QuestDebug1 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Arpan";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Arpan));
+ next;
+
+ GenericQuestDebug ShipQuests_Arpan,
+ l("Arpan is waiting for you"), 0,
+ l("Arpan told you to open the chest"), 1,
+ l("You opened the chest"), 2,
+ l("Completed"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/002-ShipQuests_Alige.txt b/npc/functions/quest-debug/002-ShipQuests_Alige.txt
new file mode 100644
index 00000000..36d0ce23
--- /dev/null
+++ b/npc/functions/quest-debug/002-ShipQuests_Alige.txt
@@ -0,0 +1,27 @@
+// Alige quest debug
+// Author:
+// gumi
+
+function script QuestDebug2 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Alige";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Alige));
+ next;
+
+ GenericQuestDebug ShipQuests_Alige,
+ l("Does not have the quest"), 0,
+ l("First encounter"), 1,
+ l("Alige asks for food"), 2,
+ l("Completed"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/003-ShipQuests_Peter.txt b/npc/functions/quest-debug/003-ShipQuests_Peter.txt
new file mode 100644
index 00000000..4732d238
--- /dev/null
+++ b/npc/functions/quest-debug/003-ShipQuests_Peter.txt
@@ -0,0 +1,36 @@
+// Peter quest debug
+// Author:
+// gumi
+// jesusalva
+// Notes:
+// Using l() usually is not a good idea (translating debug text? What?)
+
+function script QuestDebug3 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Peter";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Peter));
+ mes l("Killed mob bitmask: @@", getq2(ShipQuests_Peter));
+ mes l("Instance ID: @@", getq3(ShipQuests_Peter));
+ next;
+
+ .@q=getq(ShipQuests_Peter);
+
+ GenericQuestDebug ShipQuests_Peter,
+ l("Does not have the quest"), 0,
+ l("Peter needs help"), 1,
+ l("Toggle Tortuga Bounty"), .@q^2,
+ l("Toggle Ratto Bounty"), .@q^4,
+ l("Toggle Croc Bounty"), .@q^8,
+ l("Quest complete"), 15;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/004-ShipQuests_Nard.txt b/npc/functions/quest-debug/004-ShipQuests_Nard.txt
new file mode 100644
index 00000000..9ec51cd8
--- /dev/null
+++ b/npc/functions/quest-debug/004-ShipQuests_Nard.txt
@@ -0,0 +1,38 @@
+// Nard quest debug
+// Author:
+// gumi
+
+function script QuestDebug4 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Nard";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Nard));
+ mes "---";
+ mes l("Subquests:");
+ mes "ShipQuests_Gugli: " + getq(ShipQuests_Gugli);
+ mes "ShipQuests_ChefGado: " + getq(ShipQuests_ChefGado);
+ next;
+
+ GenericQuestDebug ShipQuests_Nard,
+ l("Does not have the quest"), 0,
+ l("Nard asks to help crew"), 1,
+ menuimage("actions/manage", l("Debug Gugli quest")), -1,
+ l("Completed Gugli's task"), 2,
+ l("Nard asks to solve conflict"), 3,
+ menuimage("actions/manage", l("Debug Gado quest")), -2,
+ l("Solved conflict"), 4,
+ l("Official crew member"), 5,
+ l("Talked to narrator"), 6;
+
+ switch (@menuret)
+ {
+ case -1: callfunc "QuestDebug16"; break;
+ case -2: callfunc "QuestDebug17"; break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/005-ShipQuests_Knife.txt b/npc/functions/quest-debug/005-ShipQuests_Knife.txt
new file mode 100644
index 00000000..a5ec1ae8
--- /dev/null
+++ b/npc/functions/quest-debug/005-ShipQuests_Knife.txt
@@ -0,0 +1,25 @@
+// Knife quest debug
+// Author:
+// gumi
+
+function script QuestDebug5 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Knife";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Knife));
+ next;
+
+ GenericQuestDebug ShipQuests_Knife,
+ l("Does not have the quest"), 0,
+ l("Got the knife"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/006-ShipQuests_ArpanMoney.txt b/npc/functions/quest-debug/006-ShipQuests_ArpanMoney.txt
new file mode 100644
index 00000000..0f77c1b9
--- /dev/null
+++ b/npc/functions/quest-debug/006-ShipQuests_ArpanMoney.txt
@@ -0,0 +1,27 @@
+// Money quest debug
+// Author:
+// gumi
+
+function script QuestDebug6 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_ArpanMoney";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_ArpanMoney));
+ next;
+
+ GenericQuestDebug ShipQuests_ArpanMoney,
+ l("Does not have the quest"), 0,
+ l("Elmo told about money"), 1,
+ l("Arpan gave money"), 2,
+ l("Arpan gave clothes"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/007-ShipQuests_Door.txt b/npc/functions/quest-debug/007-ShipQuests_Door.txt
new file mode 100644
index 00000000..88aa00ab
--- /dev/null
+++ b/npc/functions/quest-debug/007-ShipQuests_Door.txt
@@ -0,0 +1,25 @@
+// Door quest debug
+// Author:
+// gumi
+
+function script QuestDebug7 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Door";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Door));
+ next;
+
+ GenericQuestDebug ShipQuests_Door,
+ l("Does not have the quest"), 0,
+ l("Heard conversation"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/008-ShipQuests_Couwan.txt b/npc/functions/quest-debug/008-ShipQuests_Couwan.txt
new file mode 100644
index 00000000..3df0cdbf
--- /dev/null
+++ b/npc/functions/quest-debug/008-ShipQuests_Couwan.txt
@@ -0,0 +1,26 @@
+// Couwan quest debug
+// Author:
+// gumi
+
+function script QuestDebug8 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Couwan";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Couwan));
+ next;
+
+ GenericQuestDebug ShipQuests_Couwan,
+ l("Does not have the quest"), 0,
+ l("Couwan asks to deliver box"), 1,
+ l("Delivered box, got reward"), 2;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/009-ShipQuests_TreasureChest.txt b/npc/functions/quest-debug/009-ShipQuests_TreasureChest.txt
new file mode 100644
index 00000000..97adef46
--- /dev/null
+++ b/npc/functions/quest-debug/009-ShipQuests_TreasureChest.txt
@@ -0,0 +1,25 @@
+// Treasure chest quest debug
+// Author:
+// gumi
+
+function script QuestDebug9 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_TreasureChest";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_TreasureChest));
+ next;
+
+ GenericQuestDebug ShipQuests_TreasureChest,
+ l("Does not have the quest"), 0,
+ l("Opened treasure chest"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/010-ShipQuests_Ale.txt b/npc/functions/quest-debug/010-ShipQuests_Ale.txt
new file mode 100644
index 00000000..e5422122
--- /dev/null
+++ b/npc/functions/quest-debug/010-ShipQuests_Ale.txt
@@ -0,0 +1,25 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug10 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Ale";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Ale));
+ next;
+
+ GenericQuestDebug ShipQuests_Ale,
+ l("Does not have the quest"), 0,
+ l("Got the package"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/011-ShipQuests_Astapolos.txt b/npc/functions/quest-debug/011-ShipQuests_Astapolos.txt
new file mode 100644
index 00000000..aca065ed
--- /dev/null
+++ b/npc/functions/quest-debug/011-ShipQuests_Astapolos.txt
@@ -0,0 +1,25 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug11 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Astapolos";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Astapolos));
+ next;
+
+ GenericQuestDebug ShipQuests_Astapolos,
+ l("Does not have the quest"), 0,
+ l("Got the package"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/012-ShipQuests_Gulukan.txt b/npc/functions/quest-debug/012-ShipQuests_Gulukan.txt
new file mode 100644
index 00000000..fac7ccde
--- /dev/null
+++ b/npc/functions/quest-debug/012-ShipQuests_Gulukan.txt
@@ -0,0 +1,25 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug12 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Gulukan";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Gulukan));
+ next;
+
+ GenericQuestDebug ShipQuests_Gulukan,
+ l("Does not have the quest"), 0,
+ l("Got the package"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/013-ShipQuests_Jalad.txt b/npc/functions/quest-debug/013-ShipQuests_Jalad.txt
new file mode 100644
index 00000000..9ae6ed2a
--- /dev/null
+++ b/npc/functions/quest-debug/013-ShipQuests_Jalad.txt
@@ -0,0 +1,25 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug13 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Jalad";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Jalad));
+ next;
+
+ GenericQuestDebug ShipQuests_Jalad,
+ l("Does not have the quest"), 0,
+ l("Got the package"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/014-ShipQuests_QMuller.txt b/npc/functions/quest-debug/014-ShipQuests_QMuller.txt
new file mode 100644
index 00000000..8a25ee65
--- /dev/null
+++ b/npc/functions/quest-debug/014-ShipQuests_QMuller.txt
@@ -0,0 +1,25 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug14 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_QMuller";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_QMuller));
+ next;
+
+ GenericQuestDebug ShipQuests_QMuller,
+ l("Does not have the quest"), 0,
+ l("Got the package"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/015-ShipQuests_Tibbo.txt b/npc/functions/quest-debug/015-ShipQuests_Tibbo.txt
new file mode 100644
index 00000000..84280ebf
--- /dev/null
+++ b/npc/functions/quest-debug/015-ShipQuests_Tibbo.txt
@@ -0,0 +1,25 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug15 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Tibbo";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Tibbo));
+ next;
+
+ GenericQuestDebug ShipQuests_Tibbo,
+ l("Does not have the quest"), 0,
+ l("Got the package"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/016-ShipQuests_Gugli.txt b/npc/functions/quest-debug/016-ShipQuests_Gugli.txt
new file mode 100644
index 00000000..e4868ff4
--- /dev/null
+++ b/npc/functions/quest-debug/016-ShipQuests_Gugli.txt
@@ -0,0 +1,48 @@
+// Part of Gugli quest debug
+// Author:
+// gumi
+
+function script QuestDebug16 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_Gugli";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_Gugli));
+ mes "---";
+ mes l("Subquests:");
+ mes "ShipQuests_Ale: " + getq(ShipQuests_Ale);
+ mes "ShipQuests_Astapolos: " + getq(ShipQuests_Astapolos);
+ mes "ShipQuests_Gulukan: " + getq(ShipQuests_Gulukan);
+ mes "ShipQuests_Jalad: " + getq(ShipQuests_Jalad);
+ mes "ShipQuests_QMuller: " + getq(ShipQuests_QMuller);
+ mes "ShipQuests_Tibbo: " + getq(ShipQuests_Tibbo);
+ next;
+
+ GenericQuestDebug ShipQuests_Gugli,
+ l("Does not have the quest"), 0,
+ l("Gugli asks to collect packages"), 1,
+ menuimage("actions/manage", l("Reset subquests")), -1,
+ menuimage("actions/manage", l("Set subquests as completed")), -2,
+ l("Got reward from gugli"), 2;
+
+ switch (@menuret)
+ {
+ case 0:
+ case 2:
+ case -1:
+ case -2:
+ .@v = (@menuret == -2 || @menuret == 2);
+ setq ShipQuests_Ale, .@v;
+ setq ShipQuests_Astapolos, .@v;
+ setq ShipQuests_Gulukan, .@v;
+ setq ShipQuests_Jalad, .@v;
+ setq ShipQuests_QMuller, .@v;
+ setq ShipQuests_Tibbo, .@v;
+ break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/017-ShipQuests_ChefGado.txt b/npc/functions/quest-debug/017-ShipQuests_ChefGado.txt
new file mode 100644
index 00000000..05e8cdb0
--- /dev/null
+++ b/npc/functions/quest-debug/017-ShipQuests_ChefGado.txt
@@ -0,0 +1,30 @@
+// Gado quest debug
+// Author:
+// gumi
+
+function script QuestDebug17 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ShipQuests_ChefGado";
+ mes "---";
+ mes l("Quest state: @@", getq(ShipQuests_ChefGado));
+ next;
+
+ GenericQuestDebug ShipQuests_ChefGado,
+ l("Does not have the quest"), 0,
+ l("Nard asks to solve conflict"), 1,
+ l("Got poison from Gado"), 2,
+ l("Poisoned Julia"), 3,
+ l("Completed, Gado wins"), 4,
+ l("Completed, Julia wins (returned poison)"), 5,
+ l("Completed, Julia wins"), 6;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/018-General_Cookies.txt b/npc/functions/quest-debug/018-General_Cookies.txt
new file mode 100644
index 00000000..16c7bcd7
--- /dev/null
+++ b/npc/functions/quest-debug/018-General_Cookies.txt
@@ -0,0 +1,25 @@
+// Cookie quest debug
+// Author:
+// gumi
+
+function script QuestDebug18 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Cookies";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Cookies));
+ next;
+
+ GenericQuestDebug General_Cookies,
+ l("Does not have the quest"), 0,
+ l("Got a cookie"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/020-ArtisQuests_LazyBrother.txt b/npc/functions/quest-debug/020-ArtisQuests_LazyBrother.txt
new file mode 100644
index 00000000..11cf3a44
--- /dev/null
+++ b/npc/functions/quest-debug/020-ArtisQuests_LazyBrother.txt
@@ -0,0 +1,28 @@
+// Lazy brother quest debug
+// Author:
+// gumi
+
+function script QuestDebug20 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_LazyBrother";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_LazyBrother));
+ next;
+
+ GenericQuestDebug ArtisQuests_LazyBrother,
+ l("Does not have the quest"), 0,
+ l("Katja asked for help"), 1,
+ l("Found bobo, didn't tell Katja"), 2,
+ l("Told bobo to go home"), 3,
+ l("Katja gave reward"), 4;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/021-ArtisQuests_Urchin.txt b/npc/functions/quest-debug/021-ArtisQuests_Urchin.txt
new file mode 100644
index 00000000..486cae18
--- /dev/null
+++ b/npc/functions/quest-debug/021-ArtisQuests_Urchin.txt
@@ -0,0 +1,26 @@
+// Urchin quest debug
+// Author:
+// gumi
+
+function script QuestDebug21 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_Urchin";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_Urchin));
+ next;
+
+ GenericQuestDebug ArtisQuests_Urchin,
+ l("Does not have the quest"), 0,
+ l("Moon needs @@", l("Croc Claw")), 1,
+ l("Found @@, got exp", l("Croc Claw")), 2;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/022-ArtisQuests_CatchPiou.txt b/npc/functions/quest-debug/022-ArtisQuests_CatchPiou.txt
new file mode 100644
index 00000000..9d5afc1c
--- /dev/null
+++ b/npc/functions/quest-debug/022-ArtisQuests_CatchPiou.txt
@@ -0,0 +1,26 @@
+// Piou quest debug
+// Author:
+// gumi
+
+function script QuestDebug22 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_CatchPiou";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_CatchPiou));
+ next;
+
+ GenericQuestDebug ArtisQuests_CatchPiou,
+ l("Does not have the quest"), 0,
+ l("Salem asks to catch piou"), 1,
+ l("Returned piou to Salem"), 2;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/023-ArtisQuests_Fishman.txt b/npc/functions/quest-debug/023-ArtisQuests_Fishman.txt
new file mode 100644
index 00000000..e3b5ac2e
--- /dev/null
+++ b/npc/functions/quest-debug/023-ArtisQuests_Fishman.txt
@@ -0,0 +1,26 @@
+// Eugene quest debug
+// Author:
+// gumi
+
+function script QuestDebug23 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_Fishman";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_Fishman));
+ next;
+
+ GenericQuestDebug ArtisQuests_Fishman,
+ l("Does not have the quest"), 0,
+ l("Eugene needs tentacles"), 1,
+ l("Gave tentacles, got reward"), 2;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/024-ArtisQuests_QOnan.txt b/npc/functions/quest-debug/024-ArtisQuests_QOnan.txt
new file mode 100644
index 00000000..702ef9be
--- /dev/null
+++ b/npc/functions/quest-debug/024-ArtisQuests_QOnan.txt
@@ -0,0 +1,27 @@
+// Q'Onan quest debug
+// Author:
+// gumi
+
+function script QuestDebug24 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_QOnan";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_QOnan));
+ next;
+
+ GenericQuestDebug ArtisQuests_QOnan,
+ l("Does not have the quest"), 0,
+ l("Q'Onan asks to find chest"), 1,
+ l("Found the chest"), 2,
+ l("Gave to Q'Onan, got reward"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/026-General_Rumly.txt b/npc/functions/quest-debug/026-General_Rumly.txt
new file mode 100644
index 00000000..c533c27a
--- /dev/null
+++ b/npc/functions/quest-debug/026-General_Rumly.txt
@@ -0,0 +1,27 @@
+// Rumly quest debug
+// Author:
+// gumi
+
+function script QuestDebug26 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Rumly";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Rumly));
+ next;
+
+ GenericQuestDebug General_Rumly,
+ l("Does not have the quest"), 0,
+ l("Rumly needs your help"), 1,
+ l("Rumly wants @@", l("Plushroom")), 2,
+ l("Gave @@ to Rumly", l("Plushroom")), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/027-ArtisQuests_Enora.txt b/npc/functions/quest-debug/027-ArtisQuests_Enora.txt
new file mode 100644
index 00000000..9121ceb3
--- /dev/null
+++ b/npc/functions/quest-debug/027-ArtisQuests_Enora.txt
@@ -0,0 +1,49 @@
+// Newbie quest debug
+// Author:
+// gumi
+
+function script QuestDebug27 {
+ do
+ {
+ clear();
+ setnpcdialogtitle(l("Quest debug"));
+ mes("ArtisQuests_Enora");
+ mes("---");
+ mes(l("Quest state: @@, @@",
+ getq(ArtisQuests_Enora),
+ getq2(ArtisQuests_Enora)));
+ next();
+
+ GenericQuestDebug(ArtisQuests_Enora,
+ l("Does not have the quest"), 0,
+ l("Enora asks to visit Chelios"), 1,
+ l("Chelios asks to visit Lloyd"), 2,
+ l("Lloyd gave package"), 3,
+ l("Chelios made sword"), 4,
+ l("Enora asks to visit Resa"), 5,
+ l("Resa gave package"), 6,
+ l("Enora asks to visit Q'Pid"), 7,
+ l("Lost the riddle"), 8,
+ l("Ivan gave package"), 9,
+ l("Enora asks to kill fluffies"), 10,
+ l("Completed, got reward"), 11);
+
+ switch (@menuret)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10: setq(ArtisQuests_Enora, getq(ArtisQuests_Enora), 0); break;
+ case 11: setq(ArtisQuests_Enora, getq(ArtisQuests_Enora), 10); break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/029-ArtisQuests_Fexil.txt b/npc/functions/quest-debug/029-ArtisQuests_Fexil.txt
new file mode 100644
index 00000000..9c0d7945
--- /dev/null
+++ b/npc/functions/quest-debug/029-ArtisQuests_Fexil.txt
@@ -0,0 +1,27 @@
+// Fexil quest debug
+// Author:
+// gumi
+
+function script QuestDebug29 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_Fexil";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_Fexil));
+ next;
+
+ GenericQuestDebug ArtisQuests_Fexil,
+ l("Does not have the quest"), 0,
+ l("Lloyd gave pass"), 1,
+ l("Fexil needs help"), 2,
+ l("Fexil wants to buy fur"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/030-ArtisQuests_Lloyd.txt b/npc/functions/quest-debug/030-ArtisQuests_Lloyd.txt
new file mode 100644
index 00000000..0afb019c
--- /dev/null
+++ b/npc/functions/quest-debug/030-ArtisQuests_Lloyd.txt
@@ -0,0 +1,25 @@
+// Lloyd quest debug
+// Author:
+// gumi
+
+function script QuestDebug30 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_Lloyd";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_Lloyd));
+ next;
+
+ GenericQuestDebug ArtisQuests_Lloyd,
+ l("Does not have the quest"), 0,
+ l("Registered"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/031-General_Janus.txt b/npc/functions/quest-debug/031-General_Janus.txt
new file mode 100644
index 00000000..f97b4fbe
--- /dev/null
+++ b/npc/functions/quest-debug/031-General_Janus.txt
@@ -0,0 +1,31 @@
+// Janus quest debug
+// Author:
+// gumi
+
+function script QuestDebug31 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Janus";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Janus));
+ next;
+
+ GenericQuestDebug General_Janus,
+ l("Does not have the quest"), 0,
+ l("Talked to Janus"), 1,
+ l("Can create party"), 2,
+ l("Can create guild"), 3;
+
+ switch (@menuret)
+ {
+ case 0:
+ case 1: skill NV_BASIC, min(6, getskilllv(NV_BASIC)), 0; break;
+ case 2:
+ case 3: skill NV_BASIC, max(7, getskilllv(NV_BASIC)), 0; break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/032-ArtisQuests_MonaDad.txt b/npc/functions/quest-debug/032-ArtisQuests_MonaDad.txt
new file mode 100644
index 00000000..bda45b90
--- /dev/null
+++ b/npc/functions/quest-debug/032-ArtisQuests_MonaDad.txt
@@ -0,0 +1,26 @@
+// Mona quest debug
+// Author:
+// gumi
+
+function script QuestDebug32 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_MonaDad";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_MonaDad));
+ next;
+
+ GenericQuestDebug ArtisQuests_MonaDad,
+ l("Does not have the quest"), 0,
+ l("Mona's dad is missing"), 1,
+ l("Mona's dad was rescued"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/033-Artis_Legion_Progress.txt b/npc/functions/quest-debug/033-Artis_Legion_Progress.txt
new file mode 100644
index 00000000..ff6f1d16
--- /dev/null
+++ b/npc/functions/quest-debug/033-Artis_Legion_Progress.txt
@@ -0,0 +1,31 @@
+// Mona quest debug
+// Authors:
+// gumi
+// monwarez
+
+function script QuestDebug33 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "Artis_Legion_Progress";
+ mes "---";
+ mes l("Quest state: @@", getq(Artis_Legion_Progress));
+ next;
+
+ GenericQuestDebug Artis_Legion_Progress,
+ l("Does not have the quest"), 0,
+ l("Sent to training"), 1,
+ l("Finished training"), 2,
+ l("Sent to battle"), 3,
+ l("Finished battle"), 4,
+ l("Sent to Q'Anon"), 5,
+ l("Indefinite Traning"), 6;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/034-ArtisQuests_TrainingLegion.txt b/npc/functions/quest-debug/034-ArtisQuests_TrainingLegion.txt
new file mode 100644
index 00000000..ba72fd07
--- /dev/null
+++ b/npc/functions/quest-debug/034-ArtisQuests_TrainingLegion.txt
@@ -0,0 +1,28 @@
+// Training Legion quest
+// Authors:
+// omatt
+
+function script QuestDebug34 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArtisQuests_TrainingLegion";
+ mes "---";
+ mes l("Quest state: @@", getq(ArtisQuests_TrainingLegion));
+ next;
+
+ GenericQuestDebug ArtisQuests_TrainingLegion,
+ l("Does not have the quest"), 0,
+ l("Finished sword training"), 1,
+ l("Finished bow training"), 2,
+ l("Both sword and bow training are finished"), 3,
+ l("Skill training finished, end of quest"), 4;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/035-ThiefQuests_Artis.txt b/npc/functions/quest-debug/035-ThiefQuests_Artis.txt
new file mode 100644
index 00000000..83f9fb9c
--- /dev/null
+++ b/npc/functions/quest-debug/035-ThiefQuests_Artis.txt
@@ -0,0 +1,38 @@
+// Artis Thieves quest debug
+// Author:
+// Jesusalva
+// Field 2: Internal use (gearwheels - odd: collected; even: used)
+// Field 3: Internal use (Archive where the file is)
+
+function script QuestDebug35 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ThiefQuests_Artis";
+ mes "---";
+ mes l("Quest state: @@", getq(ThiefQuests_Artis));
+ .@q2=getq2(ThiefQuests_Artis);
+ mesf ("Gearwheels: %d (%s)", .@q2/2, (.@q2 % 2 ? "found" : "not found"));
+ mesf ("Henry's file: %d", getq3(ThiefQuests_Artis));
+ next;
+
+ GenericQuestDebug ThiefQuests_Artis,
+ ("Does not have the quest"), 0,
+ ("Accepted Townhall Quest"), 1,
+ ("Townhall arc complete"), 2,
+ ("Reward taken"), 3,
+ ("Accepted Legion Quest"), 4,
+ ("Legion arc comlete"), 5,
+ ("Reward taken (2)"), 6,
+ ("Nunia Quest Accepted"), 7,
+ ("Nunia arc comlete"), 8,
+ ("Reward taken (3)"), 9;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/050-HurnscaldQuests_Hinnak.txt b/npc/functions/quest-debug/050-HurnscaldQuests_Hinnak.txt
new file mode 100644
index 00000000..31183eb8
--- /dev/null
+++ b/npc/functions/quest-debug/050-HurnscaldQuests_Hinnak.txt
@@ -0,0 +1,32 @@
+// Hinnak quest debug
+// Author:
+// gumi
+
+function script QuestDebug50 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_Hinnak";
+ mes "---";
+ mes l("Quest state: @@, @@",
+ getq(HurnscaldQuests_Hinnak),
+ getq2(HurnscaldQuests_Hinnak));
+ next;
+
+ GenericQuestDebug HurnscaldQuests_Hinnak,
+ l("Cannot do the quest"), 0,
+ l("Can do the quest"), 1,
+ l("Hinnak asked for help"), 2,
+ l("Helped Hinnak"), 3;
+
+ switch (@menuret)
+ {
+ case 0:
+ case 1:
+ case 2: setq HurnscaldQuests_Hinnak, getq(HurnscaldQuests_Hinnak), 0; break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/051-HurnscaldQuests_Soup.txt b/npc/functions/quest-debug/051-HurnscaldQuests_Soup.txt
new file mode 100644
index 00000000..44694f06
--- /dev/null
+++ b/npc/functions/quest-debug/051-HurnscaldQuests_Soup.txt
@@ -0,0 +1,32 @@
+// Mikhail & Bernard quest debug
+// Author:
+// gumi
+
+function script QuestDebug51 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_Soup";
+ mes "---";
+ mes l("Quest state: @@",
+ getq(HurnscaldQuests_Soup));
+ next;
+
+ GenericQuestDebug HurnscaldQuests_Soup,
+ l("Cannot do the quest"), 0,
+ l("Can do the quest"), 1,
+ l("Bernard wants roasted maggot"), 2,
+ l("brought maggot"), 3,
+ l("Bernard wants maggot slime"), 4,
+ l("brought maggot slime"), 5,
+ l("Mikhail needs maggot slime"), 6,
+ l("brought maggot slime"), 7;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/052-HurnscaldQuests_Inspector.txt b/npc/functions/quest-debug/052-HurnscaldQuests_Inspector.txt
new file mode 100644
index 00000000..72d99242
--- /dev/null
+++ b/npc/functions/quest-debug/052-HurnscaldQuests_Inspector.txt
@@ -0,0 +1,41 @@
+// Inspector quest debug
+// Author:
+// gumi
+
+function script QuestDebug52 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_Inspector";
+ mes "---";
+ mes l("Quest state: @@",
+ getq(HurnscaldQuests_Inspector));
+ next;
+
+ GenericQuestDebug HurnscaldQuests_Inspector,
+ l("Cannot do the quest"), 0,
+ l("Can do the quest"), 1,
+ l("Talked to Inspector (1)"), 2,
+ l("Talked to Old Woman (1)"), 3,
+ l("Talked to Old Woman (2)"), 4,
+ l("Talked to Inspector (2)"), 5,
+ l("Talked to Troupe Leader (1)"), 6,
+ l("Talked to Inspector (3)"), 7,
+ l("Talked to Old Man"), 8,
+ l("Talked to Old Woman (3)"), 9,
+ l("Talked to Inspector (4)"), 10,
+ l("Talked to Old Woman (4)"), 11,
+ l("Talked to Malek"), 12,
+ l("Searched the bookcase"), 13,
+ l("Talked to Inspector (5)"), 14,
+ l("Talked to Troupe Leader (2)"), 15,
+ l("Talked to Inspector (6)"), 16;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/053-HurnscaldQuests_ForestBow.txt b/npc/functions/quest-debug/053-HurnscaldQuests_ForestBow.txt
new file mode 100644
index 00000000..2a0993e3
--- /dev/null
+++ b/npc/functions/quest-debug/053-HurnscaldQuests_ForestBow.txt
@@ -0,0 +1,42 @@
+// Jack Lumber quest debug
+// Author:
+// gumi
+
+function script QuestDebug53 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_ForestBow";
+ mes "---";
+ mes l("Quest state: @@", getq(HurnscaldQuests_ForestBow));
+ mes "---";
+ mes l("Related quests:");
+ mes "HurnscaldQuests_WoodenShield: " + getq(HurnscaldQuests_WoodenShield);
+ next;
+
+ GenericQuestDebug HurnscaldQuests_ForestBow,
+ menuimage("actions/manage", l("Debug Wooden Shield")), -1,
+ l("Cannot do the quest"), 0,
+ l("Can do the quest"), 1,
+ l("Alan wants to ask Jack"), 2,
+ l("Jack explained problem"), 3,
+ l("Alan asks to find wood"), 4,
+ l("Found perfect wood"), 5,
+ l("Got the bow"), 6;
+
+ switch (@menuret)
+ {
+ case -1: callfunc "QuestDebug40"; break;
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4: setq(HurnscaldQuests_WoodenShield, 0); break;
+ case 5:
+ case 6: setq(HurnscaldQuests_WoodenShield, max(1, getq(HurnscaldQuests_WoodenShield))); break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/054-HurnscaldQuests_WoodenShield.txt b/npc/functions/quest-debug/054-HurnscaldQuests_WoodenShield.txt
new file mode 100644
index 00000000..0cb3ee9d
--- /dev/null
+++ b/npc/functions/quest-debug/054-HurnscaldQuests_WoodenShield.txt
@@ -0,0 +1,37 @@
+// Jack Lumber quest debug
+// Author:
+// gumi
+
+function script QuestDebug54 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_WoodenShield";
+ mes "---";
+ mes l("Quest state: @@", getq(HurnscaldQuests_WoodenShield));
+ mes "---";
+ mes l("Related quests:");
+ mes "HurnscaldQuests_ForestBow: " + getq(HurnscaldQuests_ForestBow);
+ next;
+
+ GenericQuestDebug HurnscaldQuests_WoodenShield,
+ menuimage("actions/manage", l("Debug Forest Bow")), -1,
+ l("Cannot do the quest"), 0,
+ l("Can do the quest"), 1,
+ l("Jack proposes shield"), 2,
+ l("Accepted the quest"), 3,
+ l("Got the shield"), 4;
+
+ switch (@menuret)
+ {
+ case -1: callfunc "QuestDebug39"; break;
+ case 1:
+ case 2:
+ case 3:
+ case 4: setq(HurnscaldQuests_ForestBow, max(5, getq(HurnscaldQuests_ForestBow))); break;
+ default: if (@menuret < 0) return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/055-General_Cooking.txt b/npc/functions/quest-debug/055-General_Cooking.txt
new file mode 100644
index 00000000..ec725364
--- /dev/null
+++ b/npc/functions/quest-debug/055-General_Cooking.txt
@@ -0,0 +1,92 @@
+// Cooking quest debug
+// Author:
+// Jesusalva
+
+function script QuestDebug55 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Cooking";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Cooking));
+ mes l("Route choosen: %s", (getq2(General_Cooking) == VEGAN ? l("Vegan") : l("Carnivorous")));
+ mes l("Known Recipes: @@", array_entries(RECIPES));
+ next;
+
+ menuint
+ l("Return"), -1,
+ l("Reset Quest"), 0,
+ "[2] Completed Yannika's Quest", 2,
+ "[3] Accepted Yannika's Request for Seafood Plate", 3,
+ "[4] Delivered fish to Dimond's Inn", 4,
+ "[5] Accepted task to talk to Reid's Inn", 5,
+ "[6] Got request for Piou/Manana Sandwhich", 6,
+ "[7] Got sent to Candor Inn", 7,
+ "[8] Tiki asked for new idea", 8,
+ "[9] Tiki approved new idea", 9,
+ "[10] Reid's Chef gave you epic recipe", 10,
+ "[11] Sent to tulimshar bakery", 11,
+ "[12] Sent to bakery apprentice", 12,
+ "[13] Killed all rattos", 13,
+ "[14] Learned Donut recipe", 14,
+ "[15] Sent to search for Salad", 15,
+ "[16] Offered to bring stuff to Hocus", 16,
+ "[17] Received Hocus' Salad", 17,
+ "[18] Salad Delivered", 18,
+ "[19] Quest Completed", 19,
+ l("Get a Recipe Book"), -2,
+ l("Learn all recipes"), -3,
+ l("Reset all recipes"), -4;
+
+ switch (@menuret)
+ {
+ case -1:
+ break;
+ case -2:
+ getitem RecipeBook, 1;
+ break;
+ case -3:
+ RECIPES[CraftCarpSandwich]=true;
+ RECIPES[CraftMananaSandwich]=true;
+ RECIPES[CraftPioulegSandwich]=true;
+
+ RECIPES[CraftSailorStew]=true;
+ RECIPES[CraftSquirrelStew]=true;
+ RECIPES[CraftMoubooStew]=true;
+
+ RECIPES[CraftSeafoodPlate]=true;
+ RECIPES[CraftBarbecuePlate]=true;
+ RECIPES[CraftVeggiePlate]=true;
+
+ RECIPES[CraftDonut]=true;
+ RECIPES[CraftBlueberryCake]=true;
+ RECIPES[CraftCarrotCake]=true;
+ break;
+ case -4:
+ RECIPES[CraftCarpSandwich]=false;
+ RECIPES[CraftMananaSandwich]=false;
+ RECIPES[CraftPioulegSandwich]=false;
+
+ RECIPES[CraftSailorStew]=false;
+ RECIPES[CraftSquirrelStew]=false;
+ RECIPES[CraftMoubooStew]=false;
+
+ RECIPES[CraftSeafoodPlate]=false;
+ RECIPES[CraftBarbecuePlate]=false;
+ RECIPES[CraftVeggiePlate]=false;
+
+ RECIPES[CraftDonut]=false;
+ RECIPES[CraftBlueberryCake]=false;
+ RECIPES[CraftCarrotCake]=false;
+ break;
+ default:
+ setq1 General_Cooking, @menuret;
+ break;
+
+ }
+
+ return;
+
+ } while (@menu != 1);
+}
diff --git a/npc/functions/quest-debug/056-General_Brotherhood.txt b/npc/functions/quest-debug/056-General_Brotherhood.txt
new file mode 100644
index 00000000..07fe568f
--- /dev/null
+++ b/npc/functions/quest-debug/056-General_Brotherhood.txt
@@ -0,0 +1,27 @@
+// Mona quest debug
+// Authors:
+// gumi
+// monwarez
+// jesusalva
+
+function script QuestDebug56 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Brotherhood";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Brotherhood));
+ next;
+
+ GenericQuestDebug General_Brotherhood,
+ l("Does not have the quest"), 0,
+ l("Contacted by Sopiahalla"), 1;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/057-HurnscaldQuests_Kfahr.txt b/npc/functions/quest-debug/057-HurnscaldQuests_Kfahr.txt
new file mode 100644
index 00000000..4ee0b36e
--- /dev/null
+++ b/npc/functions/quest-debug/057-HurnscaldQuests_Kfahr.txt
@@ -0,0 +1,31 @@
+// Kfahr quest debug
+// Author:
+// Toams
+
+function script QuestDebug57 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_Kfahr";
+ mes "---";
+ mes l("Quest state: @@", getq(HurnscaldQuests_Kfahr));
+ //mes "---";
+ //mes l("Related quests:");
+ //mes "HurnscaldQuests_Setzer: " + getq(HurnscaldQuests_Setzer);
+ next;
+
+ GenericQuestDebug HurnscaldQuests_Kfahr,
+ menuimage("actions/manage", l("Debug Kfahr")), -1,
+ l("Didn't speak with Kfahr yet"), 0,
+ l("Already met Kfahr, No quests started"), 1,
+ l("Bone knife quest started"), 2,
+ l("Bone knife quest finished"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/058-ArgaesQuest_Galimatia.txt b/npc/functions/quest-debug/058-ArgaesQuest_Galimatia.txt
new file mode 100644
index 00000000..01a058e7
--- /dev/null
+++ b/npc/functions/quest-debug/058-ArgaesQuest_Galimatia.txt
@@ -0,0 +1,32 @@
+// Galimatia quest debug
+// Author:
+// Livio
+// Someone else I've forgot the name
+
+function script QuestDebug58 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "ArgaesQuest_Galimatia";
+ mes "---";
+ mes l("Quest state: @@", getq(ArgaesQuest_Galimatia));
+ next;
+
+ GenericQuestDebug ArgaesQuest_Galimatia,
+ l("[RESET QUEST] Does not have the quest"), 0,
+ l("PC have to pour chemicals on dirt"), 1,
+ l("Galimatia needs Fertility Potion ingredients"), 2,
+ l("PC have to pour Fertility Potion on the same spot"), 3,
+ l("Something grows or it should be"), 4,
+ l("Galimatia offers a reward"), 5,
+ l("Galimatia offers to exchange flower things"), 6;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+ return;
+} \ No newline at end of file
diff --git a/npc/functions/quest-debug/059-HurnscaldQuests_Rossy.txt b/npc/functions/quest-debug/059-HurnscaldQuests_Rossy.txt
new file mode 100644
index 00000000..85c2006b
--- /dev/null
+++ b/npc/functions/quest-debug/059-HurnscaldQuests_Rossy.txt
@@ -0,0 +1,43 @@
+// Rossy quest debug
+// Authors:
+// jesusalva
+
+function script QuestDebug59 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "HurnscaldQuests_Rossy";
+ mes "---";
+ mes l("Quest state: @@", getq(HurnscaldQuests_Rossy));
+ if (getq(HurnscaldQuests_Rossy) == 16)
+ mes l("Clauquer's Cave Mask: %d", getq2(HurnscaldQuests_Rossy));
+ next;
+
+ GenericQuestDebug HurnscaldQuests_Rossy,
+ l("Does not have the quest"), 0,
+ l("Requested to find Rossy"), 1,
+ l("Found Rossy"), 2,
+ l("Informed Olana about Rossy"), 3,
+ l("Requested to deliver the berries"), 4,
+ l("Berries delivered"), 5,
+ l("Requested to tell Rossy about exam"), 6,
+ l("Accepted to help Rossy"), 7,
+ l("Requested to deliver potion to David"), 8,
+ l("Delivered potion to David"), 9,
+ l("Inform Olana about success"), 10,
+ l("Bring roses to Rossy"), 11,
+ l("Talk to Olana about allergy"), 12,
+ l("Bring tulips to Rossy"), 13,
+ l("Say Olana is a good mother"), 14,
+ l("Get status on Juliet with Rossy"), 15,
+ l("Dispatched to Clauquer Cave"), 16,
+ l("Juliet has been rescued"), 17;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/061-General_Hal.txt b/npc/functions/quest-debug/061-General_Hal.txt
new file mode 100644
index 00000000..172108f4
--- /dev/null
+++ b/npc/functions/quest-debug/061-General_Hal.txt
@@ -0,0 +1,30 @@
+// Hal quest debug
+// Author:
+// Livio
+
+function script QuestDebug61 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_CptHal";
+ mes "---";
+ mes l("Quest state: @@", getq(General_CptHal));
+ next;
+
+ GenericQuestDebug General_CptHal,
+ l("[RESET QUEST] Does not have the quest"), 0,
+ l("Bothered to talk to Thamas"), 1,
+ l("Accepted to resupply Hal's Legion troop"), 2,
+ l("Looking for Sergeant Ryan"), 3,
+ l("Found Sergeant Ryan, looking for items"), 4,
+ l("Healed Sergeant Ryan"), 5;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+ return;
+} \ No newline at end of file
diff --git a/npc/functions/quest-debug/100-General_Narrator.txt b/npc/functions/quest-debug/100-General_Narrator.txt
new file mode 100644
index 00000000..a88f5d6a
--- /dev/null
+++ b/npc/functions/quest-debug/100-General_Narrator.txt
@@ -0,0 +1,27 @@
+// Narrator debug
+// Author:
+// gumi
+
+function script QuestDebug100 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Narrator";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Narrator));
+ next;
+
+ GenericQuestDebug General_Narrator,
+ l("Game introduction"), 0,
+ l("Arrived in Artis"), 1,
+ l("Arrived in Argaes"), 2,
+ l("Sent to Airlia"), 3;
+
+ if (@menuret < 0)
+ {
+ return;
+ }
+
+ } while (1);
+}
diff --git a/npc/functions/quest-debug/functions.txt b/npc/functions/quest-debug/functions.txt
new file mode 100644
index 00000000..e45cb427
--- /dev/null
+++ b/npc/functions/quest-debug/functions.txt
@@ -0,0 +1,109 @@
+// Evol functions.
+// Author:
+// gumi
+// Description:
+// generic quest debug functions
+
+
+
+// GenericQuestDebug
+// makes a generic quest debug menu for the given quest when the server
+// is in debug mode.
+
+function script GenericQuestDebug {
+ if (!debug && !is_admin())
+ {
+ select
+ menuimage("actions/back", l("Go back"));
+
+ @menuret = -0x7FFFFFFF;
+ return 1;
+ }
+
+ mes l("Choose desired quest state:");
+
+ deletearray .@vals;
+ .@menustr$ = menuimage("actions/abort", l("Do nothing")) + ":";
+ .@vals[0] = -0x7FFFFFFF;
+ .@cnt = 1;
+
+ for (.@f = 1; .@f < getargcount(); .@f += 2)
+ {
+ if (getarg(.@f) != "")
+ {
+ .@qv = getarg(.@f + 1);
+ .@s$ = menuimage("actions/" + (.@qv ? "edit" : "reset"), "[" + .@qv + "] " + getarg(.@f));
+ .@menustr$ += (.@qv < 0 ? getarg(.@f) : .@s$) + ":";
+ .@vals[.@cnt] = .@qv;
+ ++.@cnt;
+ }
+ }
+
+ if (is_admin())
+ {
+ .@menustr$ += menuimage("actions/nuke", l("Set state manually"));
+ .@vals[.@cnt] = -0x7FFFFFFE;
+ }
+
+
+ @menu = 255;
+ @menuret = -1;
+ select(.@menustr$);
+ if (@menu == 255)
+ return -1;
+
+ --@menu;
+ if (@menu < 0 || @menu >= getarraysize(.@vals))
+ return -1;
+
+ @menuret = .@vals[@menu];
+
+ switch (@menuret)
+ {
+ case -0x7FFFFFFE: input @menuret; setq getarg(0,0), @menuret;
+ case -0x7FFFFFFF: return 1;
+ }
+
+ if (@menuret >= 0)
+ {
+ setq getarg(0,0), @menuret;
+ }
+ return;
+}
+
+
+
+// selectd
+// like a normal select() but gives access to quest debug
+//
+// quest id can either be passed as first argument
+// or as the .quest_debug npc variable
+
+function script selectd {
+ .@menustr$ = rif(debug, menuaction(l("debug")));
+ .@count = getargcount();
+ .@f = 0;
+ .@questID = getvariableofnpc(.quest_debug, strnpcinfo(0));
+
+ if (.@count > 1 && !isstr(getarg(0)))
+ {
+ ++.@f;
+ .@questID = getarg(0);
+ }
+
+ for (; .@f < .@count; ++.@f)
+ {
+ .@menustr$ += ":" + getarg(.@f);
+ }
+
+ @menu = 255;
+ select .@menustr$;
+
+ switch (@menu)
+ {
+ case -1:
+ case 255: return -1;
+ default: @menu -= 1; return @menu; // FIXME: here I would have done `return --@menu;` but hercules prevents this
+ case 1: callfunc "QuestDebug" + .@questID; closeclientdialog; end;
+ }
+}
diff --git a/npc/functions/questgen.txt b/npc/functions/questgen.txt
new file mode 100644
index 00000000..285924cb
--- /dev/null
+++ b/npc/functions/questgen.txt
@@ -0,0 +1,38 @@
+// Evol functions.
+// Authors:
+// monwarez
+// Reid
+// Description:
+// Generate a random quest type and location.
+// Variables:
+// @quests : 2D array containing quest type and location availability
+// with @nb_type rows and @nb_location columns.
+// boolean value determine if the connection is possible between
+// the quest type and location selected.
+// @nb_difficulty : difficulty value from 0 to N-1.
+// Argument:
+// 0 : quest type
+// 1 : quest location
+// 2 : quest difficulty
+// Return : Tridimentional array value;
+
+function script questgen {
+
+ .@argc = getargcount();
+ @q_type = getarg(0, rand(@nb_type * 10) / 10);
+
+ do
+ {
+ @q_location = getarg(1, rand(@nb_location * 10) / 10);
+ .@cell = @q_type * @nb_location + @q_location;
+
+ if (!@quests[.@cell] && .@argc >= 2)
+ {
+ return false;
+ }
+ } while (!@quests[.@cell]);
+
+ @q_difficulty = getarg(2, rand(@nb_difficulty * 10) / 10);
+
+ return true;
+}
diff --git a/npc/functions/referral.txt b/npc/functions/referral.txt
new file mode 100644
index 00000000..824a415b
--- /dev/null
+++ b/npc/functions/referral.txt
@@ -0,0 +1,43 @@
+// The Mana World scripts.
+// Author:
+// Moubootaur Legends Team
+// Jesusalva
+// gumi
+// Description:
+// Referral System - rewards
+// Note: Does not support multi-levelup
+
+function script ReferralSendLvReward {
+ .@refVault = bitwise_get(getvaultvar(REFERRAL_PROG), 0x00FFFFFF, 0); // the unique identifier of the referrer (Vault/account ID) [24-bit integer]
+ .@status = bitwise_get(getvaultvar(REFERRAL_PROG), 0x7F000000, 24); // the last reward obtained [8-bit integer]
+
+ if (.@refVault < 1) {
+ // the player has not been referred
+ return;
+ }
+
+ .@refChar = "playerCache"::vault2char(.@refVault);
+
+ if (.@refChar < 1) {
+ // the referrer no longer exists: unassign it
+ setvaultvar(REFERRAL_PROG, false);
+ return;
+ }
+
+ setarray(.@rewardTiers[0], 25, 50, 75, 100);
+ .@tier = array_find(.@rewardTiers[0], BaseLevel);
+
+ if (.@tier < 0 || .@status > .@tier) {
+ // not a reward tier, or already claimed
+ return;
+ }
+
+ rodex_sendmail(.@refChar, "TMW Team",
+ sprintf("Referred player reached Lv %i!", BaseLevel),
+ sprintf("%s just reached level %i!\n"
+ "As they get stronger, more rewards will be sent to you!", strcharinfo(PC_NAME), BaseLevel),
+ 0, Acorn, 1);
+
+ bitwise_set(getvaultvar(REFERRAL_PROG), 0x7F000000, 24, .@tier);
+ return;
+}
diff --git a/npc/functions/refine.txt b/npc/functions/refine.txt
new file mode 100644
index 00000000..23df387c
--- /dev/null
+++ b/npc/functions/refine.txt
@@ -0,0 +1,66 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Inspiration:
+// Pyndragon (LoF)
+// Scall (TMW-BR)
+// Saulc (ML)
+// Description:
+// Handles refinement
+
+// refineupdate( {killedrid} )
+function script refineupdate {
+ // Not armed? We do nothing
+ if (!getequipisequiped(EQI_HAND_R))
+ return;
+
+ // Set temporary variables
+ .@k=getarg(0, killedrid);
+ .@w=getequipid(EQI_HAND_R);
+ .@r=getequiprefinerycnt(EQI_HAND_R);
+
+
+ // Weapon cannot be refined
+ if (!getequipisenableref(EQI_HAND_R))
+ return;
+
+ // Register the weapon experience
+ weaponExp[.@w] = weaponExp[.@w] + getmonsterinfo(.@k, MOB_LV);
+
+ // Get exp needed to level up from global array
+ .@exp=$@REFEXP[.@r];
+
+ // Cannot level up
+ if (.@exp < 1)
+ return;
+
+ // Leveled up!
+ if (weaponExp[.@w] >= .@exp) {
+ weaponExp[.@w]-=.@exp;
+ weaponLvl[.@w] = weaponLvl[.@w] + 1;
+ successrefitem(EQI_HAND_R);
+ dispbottom l("Weapon level up!");
+ }
+ return;
+}
+
+// Resyncs weapon level
+function script refinesync {
+ // Not armed? We do nothing
+ if (!getequipisequiped(EQI_HAND_R))
+ return;
+
+ .@w=getequipid(EQI_HAND_R);
+ .@r=getequiprefinerycnt(EQI_HAND_R);
+ .@lv=weaponLvl[.@w];
+
+ if (.@r > .@lv) {
+ // Refine level overestimated
+ downrefitem(EQI_HAND_R, max(0, .@r - .@lv));
+ } else if (.@lv > .@r) {
+ // Refine level understimated
+ successrefitem(EQI_HAND_R, max(0, .@lv - .@r));
+ }
+ return;
+}
+
diff --git a/npc/functions/resetstatus.txt b/npc/functions/resetstatus.txt
new file mode 100644
index 00000000..d5d4fdda
--- /dev/null
+++ b/npc/functions/resetstatus.txt
@@ -0,0 +1,117 @@
+// Moubootaur Legends Script.
+// Authors:
+// Vasily_Makarov (original from Evol)
+// Jesusalva
+// Description:
+// Status Reset NPC utils
+
+// Reset status and return permanent bonuses
+// StatusResetReinvest( {script=True} )
+function script StatusResetReinvest {
+ /* XXX: Uncommment this for ML Permanent Boost Status Fruit System :XXX
+ // Compulsory check
+ if (getarg(0, true)) {
+ inventoryplace NPCEyes, 6;
+ } else if (!checkweight(NPCEyes, 6)) {
+ getitembound StatusResetPotion, 1, 4;
+ dispbottom l("You cannot carry the fruits.");
+ end; // Die
+ }
+
+ // Permanent boosts were now lost, return the fruits
+ if (STATUSUP_STR) {
+ getitembound StrengthFruit, STATUSUP_STR, 4;
+ STATUSUP_STR=0;
+ }
+ if (STATUSUP_AGI) {
+ getitembound AgilityFruit, STATUSUP_AGI, 4;
+ STATUSUP_AGI=0;
+ }
+ if (STATUSUP_VIT) {
+ getitembound VitalityFruit, STATUSUP_VIT, 4;
+ STATUSUP_VIT=0;
+ }
+ if (STATUSUP_INT) {
+ getitembound IntelligenceFruit, STATUSUP_INT, 4;
+ STATUSUP_INT=0;
+ }
+ if (STATUSUP_DEX) {
+ getitembound DexterityFruit, STATUSUP_DEX, 4;
+ STATUSUP_DEX=0;
+ }
+ if (STATUSUP_LUK) {
+ getitembound LuckFruit, STATUSUP_LUK, 4;
+ STATUSUP_LUK=0;
+ }
+ */
+ resetstatus();
+ return true;
+}
+
+// Return wasSP on success, 0 on failure
+// ConfirmReset( {price} )
+function script ConfirmStatusReset {
+ if (BaseLevel >= 15)
+ .@raw_price=(1000-BaseLevel*10+(BaseLevel*18));
+ else if (BaseLevel >= 10)
+ .@raw_price=(BaseLevel*210-(10*210))/(BaseLevel/10);
+ else
+ .@raw_price=1;
+
+ if (getarg(0,-1) >= 0)
+ .@raw_price=getarg(0,-1);
+
+ //mesc l("WARNING: Permanent boosts will return to their fruit form."), 1;
+ mesc l("WARNING: Status resets cannot be reverted!"), 1;
+
+ switch (select(l("Yes, I am sure. Please reset my status!"),
+ l("I need to think about it..."),
+ l("I won't need it, thank you.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Let me just have a quick look at you. Hm... I will need %d GP to reset your stats.", .@raw_price);
+
+ select
+ rif(Zeny >= .@raw_price, l("Here, take as much as you need, I have plenty!")),
+ rif(Zeny > 0 && Zeny < .@raw_price, l("I don't have enough money...")),
+ rif(Zeny == 0, l("Oh no, I don't have any money on me right now.")),
+ l("I have to go, sorry.");
+
+ if (@menu > 1) {
+ return 0;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thank you."),
+ l("Now stand still... It should not take much time...");
+
+ // Reset status have an inventorycheck, so we charge later.
+ .@wasSP = StatusPoint;
+ StatusResetReinvest();
+
+ // Nothing to do: Do not charge (eg. you just got the fruits back)
+ if (StatusPoint == .@wasSP) {
+ speech S_LAST_NEXT,
+ l("It seems that you have no status points to reset!"),
+ l("Come back when you will really need me.");
+ } else {
+ Zeny-=.@raw_price;
+ speech S_LAST_NEXT,
+ l("Let's see... @@ of your status points have just been reset!", StatusPoint - .@wasSP),
+ l("Spend it wisely this time."),
+ l("But you are welcome to reset your stats again! I need the money.");
+ }
+ return .@wasSP;
+
+ case 2:
+ return 0;
+ case 3:
+ return 0;
+ }
+ //Exception("Unknown Error: ConfirmStatusReset() failed");
+ consolemes(CONSOLEMES_ERROR, "Unknown Error: ConfirmStatusReset() failed");
+ return 0;
+
+}
+
diff --git a/npc/functions/riddle.txt b/npc/functions/riddle.txt
new file mode 100644
index 00000000..fb503e3b
--- /dev/null
+++ b/npc/functions/riddle.txt
@@ -0,0 +1,74 @@
+// Evol functions.
+// Author:
+// Reid
+// Description:
+// Riddle enigma validator
+//
+// Arguments
+// 0 PC answer
+// 1 English correct answer
+// 2 Translated correct answer
+
+// TODO: levenshtein(), similar_text(), and maybe even soundex()
+
+function script riddlevalidation {
+ .@answer$ = strtolower(getarg(0));
+ .@good$ = strtolower(getarg(1));
+ .@good_translated$ = strtolower(getarg(2));
+
+ .@size_answer = getstrlen(.@answer$);
+ .@size_good = getstrlen(.@good$);
+ .@size_good_translated = getstrlen(.@good_translated$);
+
+ .@max = max(.@size_answer, .@size_good_translated, .@size_good);
+
+ // Input is too long.
+ if (.@max > 20)
+ {
+ return false;
+ }
+
+ .@size_good *= 70;
+ .@size_good_translated *= 70;
+
+ for (.@i = 0; .@i < .@max; .@i++)
+ {
+ .@correct = 0;
+ .@correct_translated = 0;
+
+ for (.@k = .@k_translated = .@j = .@i; .@j < .@max; .@j++)
+ {
+ if (charat(.@answer$, .@j) == charat(.@good$, .@k))
+ {
+ .@correct++;
+ .@k++;
+ }
+ else
+ {
+ .@correct--;
+ }
+
+ if (charat(.@answer$, .@j) ==
+ charat(.@good_translated$, .@k_translated))
+ {
+ .@correct_translated++;
+ .@k_translated++;
+ }
+ else
+ {
+ .@correct_translated--;
+ }
+ }
+ // if 70% of the word is correct
+ .@correct *= 100;
+ .@correct_translated *= 100;
+
+ if (.@correct >= .@size_good ||
+ .@correct_translated >= .@size_good_translated)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/npc/functions/sailordialogue.txt b/npc/functions/sailordialogue.txt
new file mode 100644
index 00000000..281246f7
--- /dev/null
+++ b/npc/functions/sailordialogue.txt
@@ -0,0 +1,53 @@
+// Evol functions.
+// Authors:
+// Qwerty Dragon
+// Reid
+// Description:
+// Random sailor dialogues between two categories of NPCs.
+
+function script sailorfood {
+ mesn;
+
+ .@q = rand(0, 400) / 100;
+ if (.@q == 0) goto L_RandomA;
+ if (.@q == 1) goto L_RandomB;
+ if (.@q > 1) goto L_RandomC;
+
+L_RandomA:
+ mesq l("Hey.");
+ next;
+ mesq l("What did Gugli say about the box? Was it ok?");
+ next;
+
+ menu
+ l("It's ok."), L_Fine,
+ l("He needs more food."), -;
+
+ mes "";
+ mesn;
+ mesq l("Oh really? I'll put more food in the next box then.");
+
+ close;
+
+L_Fine:
+ mes "";
+ mesn;
+ mesq l("It's alright! Just one more box and it'll be ok.");
+
+ close;
+
+L_RandomB:
+ mesq l("Thanks for the help!");
+ next;
+ mesq l("These boxes are way too heavy to be lifted by only one person, all the way onto the ship.");
+
+ close;
+
+L_RandomC:
+ mesq l("I think I'll be done soon, since I almost have a box full of @@s!", getitemlink(CrocClaw));
+ next;
+ mesq l("And you? How's it going on your side?");
+ next;
+
+ return;
+}
diff --git a/npc/functions/sailortalk.txt b/npc/functions/sailortalk.txt
new file mode 100644
index 00000000..73145768
--- /dev/null
+++ b/npc/functions/sailortalk.txt
@@ -0,0 +1,37 @@
+// Evol functions.
+// Author:
+// Reid
+// Description:
+// Tell a random sentence.
+// Variables:
+// .@rand = Random number between the number of sentence choice.
+
+function script sailortalk {
+
+ .@rand = rand(8);
+ if (.@rand == 0) goodbye;
+ if (.@rand == 1)
+ {
+ speech(
+ l("These purple mushrooms are called @@s. There are plenty of 'em on this island!", getitemlink(Plushroom)),
+ l("It's a kind of mushroom that tastes like a marshmallow and looks like a plush! @@, get it?", getitemlink(Plushroom)),
+ l("These funny fungi are mushrooming all around this island. Just pick some @@s and have a try.", getitemlink(Plushroom)));
+ close;
+ }
+ if (.@rand == 2) npctalkonce(l("Good to hear from you!"));
+ if (.@rand == 3) npctalkonce(l("So finally someone has came to visit me?"));
+ if (.@rand == 4)
+ {
+ speech(
+ l("A sunny and hot day,"),
+ l("a quiet place,"),
+ l("a ground!"),
+ l("What else do you need?"));
+ close;
+ }
+ if (.@rand == 5) npctalkonce(l("A-hoy matey!"));
+ if (.@rand == 6) npctalkonce(l("We are glad captain Nard has let you join the crew!"));
+ if (.@rand == 7) npctalkonce(l("Howdy?"));
+
+ end;
+}
diff --git a/npc/functions/savepoint.txt b/npc/functions/savepoint.txt
new file mode 100644
index 00000000..46ef73e8
--- /dev/null
+++ b/npc/functions/savepoint.txt
@@ -0,0 +1,57 @@
+// Evol functions.
+// Authors:
+// gumi
+// Reid
+// Description:
+// Adds a new save point location.
+// Usage:
+// savepointparticle;
+// savepointparticle NO_INN;
+// savepointparticle map, x, y, NO_INN;
+// Description:
+// Save location with arguments:
+// getarg(0) map name,
+// getarg(1) x's value,
+// getarg(2) y's value,
+// getarg(3) INN flag.
+
+function script savepointparticle {
+
+ if (gettimetick(2) - @lastSave < 5)
+ return;
+
+ .@mapname$ = getarg(0, "");
+ .@mapx = getarg(1, -1);
+ .@mapy = getarg(2, -1);
+ .@i = 3;
+
+ if (.@mapy < 1)
+ {
+ .@npc$ = strnpcinfo(0);
+ .@mapname$ = getvariableofnpc(.map$, .@npc$);
+ .@mapx = getvariableofnpc(.x, .@npc$);
+ .@mapy = getvariableofnpc(.y, .@npc$);
+ .@i = 0;
+ }
+
+ // If this will override your current inn, a confirmation is required.
+ // Unless you already don't have a booked place, then, confirmation is never shown.
+ if (getarg(.@i, NO_INN) != INN_REGISTER && INN_REGISTER != NO_INN)
+ {
+ mesc l("Do you want to use this place as save point?");
+ mesc b(l("Warning: ")) + l("Previous Inn reservation will be lost!");
+
+ if (askyesno() != ASK_YES)
+ close;
+
+ INN_REGISTER = NO_INN;
+ }
+
+ message strcharinfo(0), l("Your position has been saved.");
+
+ savepoint .@mapname$, .@mapx, .@mapy;
+ specialeffect(4, SELF, getcharid(3));
+ @lastSave = gettimetick(2);
+
+ return;
+}
diff --git a/npc/functions/scoreboards.txt b/npc/functions/scoreboards.txt
new file mode 100644
index 00000000..616ea54a
--- /dev/null
+++ b/npc/functions/scoreboards.txt
@@ -0,0 +1,291 @@
+// Moubootaur Legends Script
+// Author:
+// Jesusalva
+// Description:
+// Leaderboards
+
+// Scoreboard functions
+function script HallOfGuild {
+ mes "";
+ mes l("##BHall Of Guild Level: TOP5##b");
+ mesf("1. %s (%d)", $@hoguild_name$[0], $@hoguild_value[0]);
+ mesf("2. %s (%d)", $@hoguild_name$[1], $@hoguild_value[1]);
+ mesf("3. %s (%d)", $@hoguild_name$[2], $@hoguild_value[2]);
+ mesf("4. %s (%d)", $@hoguild_name$[3], $@hoguild_value[3]);
+ mesf("5. %s (%d)", $@hoguild_name$[4], $@hoguild_value[4]);
+ return;
+}
+
+function script HallOfFortune {
+ mes "";
+ mes l("##BHall Of Fortune: TOP15##b");
+ mesf("1. %s (%s E)", $@hofortune_name$[0],format_number($@hofortune_value[0]));
+ mesf("2. %s (%s E)", $@hofortune_name$[1],format_number($@hofortune_value[1]));
+ mesf("3. %s (%s E)", $@hofortune_name$[2],format_number($@hofortune_value[2]));
+ mesf("4. %s (%s E)", $@hofortune_name$[3],format_number($@hofortune_value[3]));
+ mesf("5. %s (%s E)", $@hofortune_name$[4],format_number($@hofortune_value[4]));
+ mesf("6. %s (%s E)", $@hofortune_name$[5],format_number($@hofortune_value[5]));
+ mesf("7. %s (%s E)", $@hofortune_name$[6],format_number($@hofortune_value[6]));
+ mesf("8. %s (%s E)", $@hofortune_name$[7],format_number($@hofortune_value[7]));
+ mesf("9. %s (%s E)", $@hofortune_name$[8],format_number($@hofortune_value[8]));
+ mesf("10. %s (%s E)", $@hofortune_name$[9],format_number($@hofortune_value[9]));
+ mesf("11. %s (%s E)", $@hofortune_name$[10],format_number($@hofortune_value[10]));
+ mesf("12. %s (%s E)", $@hofortune_name$[11],format_number($@hofortune_value[11]));
+ mesf("13. %s (%s E)", $@hofortune_name$[12],format_number($@hofortune_value[12]));
+ mesf("14. %s (%s E)", $@hofortune_name$[13],format_number($@hofortune_value[13]));
+ mesf("15. %s (%s E)", $@hofortune_name$[14],format_number($@hofortune_value[14]));
+ return;
+}
+
+function script HallOfLevel {
+ mes "";
+ mes l("##BHall Of Level: TOP15##b");
+ mesf("1. %s (%d)", $@hoblvl_name$[0], $@hoblvl_value[0]);
+ mesf("2. %s (%d)", $@hoblvl_name$[1], $@hoblvl_value[1]);
+ mesf("3. %s (%d)", $@hoblvl_name$[2], $@hoblvl_value[2]);
+ mesf("4. %s (%d)", $@hoblvl_name$[3], $@hoblvl_value[3]);
+ mesf("5. %s (%d)", $@hoblvl_name$[4], $@hoblvl_value[4]);
+ mesf("6. %s (%d)", $@hoblvl_name$[5], $@hoblvl_value[5]);
+ mesf("7. %s (%d)", $@hoblvl_name$[6], $@hoblvl_value[6]);
+ mesf("8. %s (%d)", $@hoblvl_name$[7], $@hoblvl_value[7]);
+ mesf("9. %s (%d)", $@hoblvl_name$[8], $@hoblvl_value[8]);
+ mesf("10. %s (%d)", $@hoblvl_name$[9], $@hoblvl_value[9]);
+ mesf("11. %s (%d)", $@hoblvl_name$[10], $@hoblvl_value[10]);
+ mesf("12. %s (%d)", $@hoblvl_name$[11], $@hoblvl_value[11]);
+ mesf("13. %s (%d)", $@hoblvl_name$[12], $@hoblvl_value[12]);
+ mesf("14. %s (%d)", $@hoblvl_name$[13], $@hoblvl_value[13]);
+ mesf("15. %s (%d)", $@hoblvl_name$[14], $@hoblvl_value[14]);
+ return;
+}
+
+function script HallOfJob {
+ mes "";
+ mes l("##BHall Of Job Level: TOP15##b");
+ mesf("1. %s (%d)", $@hojlvl_name$[0], $@hojlvl_value[0]);
+ mesf("2. %s (%d)", $@hojlvl_name$[1], $@hojlvl_value[1]);
+ mesf("3. %s (%d)", $@hojlvl_name$[2], $@hojlvl_value[2]);
+ mesf("4. %s (%d)", $@hojlvl_name$[3], $@hojlvl_value[3]);
+ mesf("5. %s (%d)", $@hojlvl_name$[4], $@hojlvl_value[4]);
+ mesf("6. %s (%d)", $@hojlvl_name$[5], $@hojlvl_value[5]);
+ mesf("7. %s (%d)", $@hojlvl_name$[6], $@hojlvl_value[6]);
+ mesf("8. %s (%d)", $@hojlvl_name$[7], $@hojlvl_value[7]);
+ mesf("9. %s (%d)", $@hojlvl_name$[8], $@hojlvl_value[8]);
+ mesf("10. %s (%d)", $@hojlvl_name$[9], $@hojlvl_value[9]);
+ mesf("11. %s (%d)", $@hojlvl_name$[10], $@hojlvl_value[10]);
+ mesf("12. %s (%d)", $@hojlvl_name$[11], $@hojlvl_value[11]);
+ mesf("13. %s (%d)", $@hojlvl_name$[12], $@hojlvl_value[12]);
+ mesf("14. %s (%d)", $@hojlvl_name$[13], $@hojlvl_value[13]);
+ mesf("15. %s (%d)", $@hojlvl_name$[14], $@hojlvl_value[14]);
+ return;
+}
+
+function script HallOfAcorns {
+ mes "";
+ mes l("##BHall Of Acorns: TOP15##b");
+ mesc l("Only %s in storage will be counted.", getitemlink(Acorn));
+ mesf("1. %s (%d)", $@hoa_name$[0], $@hoa_value[0]);
+ mesf("2. %s (%d)", $@hoa_name$[1], $@hoa_value[1]);
+ mesf("3. %s (%d)", $@hoa_name$[2], $@hoa_value[2]);
+ mesf("4. %s (%d)", $@hoa_name$[3], $@hoa_value[3]);
+ mesf("5. %s (%d)", $@hoa_name$[4], $@hoa_value[4]);
+ mesf("6. %s (%d)", $@hoa_name$[5], $@hoa_value[5]);
+ mesf("7. %s (%d)", $@hoa_name$[6], $@hoa_value[6]);
+ mesf("8. %s (%d)", $@hoa_name$[7], $@hoa_value[7]);
+ mesf("9. %s (%d)", $@hoa_name$[8], $@hoa_value[8]);
+ mesf("10. %s (%d)", $@hoa_name$[9], $@hoa_value[9]);
+ mesf("11. %s (%d)", $@hoa_name$[10], $@hoa_value[10]);
+ mesf("12. %s (%d)", $@hoa_name$[11], $@hoa_value[11]);
+ mesf("13. %s (%d)", $@hoa_name$[12], $@hoa_value[12]);
+ mesf("14. %s (%d)", $@hoa_name$[13], $@hoa_value[13]);
+ mesf("15. %s (%d)", $@hoa_name$[14], $@hoa_value[14]);
+ return;
+}
+
+function script HallOfLethality {
+ mes "";
+ mes l("##BHall Of Lethality: TOP15##b");
+ mesc l("Special monsters are not counted.");
+ mesf("1. %s (%d)", $@hol_name$[0], $@hol_value[0]);
+ mesf("2. %s (%d)", $@hol_name$[1], $@hol_value[1]);
+ mesf("3. %s (%d)", $@hol_name$[2], $@hol_value[2]);
+ mesf("4. %s (%d)", $@hol_name$[3], $@hol_value[3]);
+ mesf("5. %s (%d)", $@hol_name$[4], $@hol_value[4]);
+ mesf("6. %s (%d)", $@hol_name$[5], $@hol_value[5]);
+ mesf("7. %s (%d)", $@hol_name$[6], $@hol_value[6]);
+ mesf("8. %s (%d)", $@hol_name$[7], $@hol_value[7]);
+ mesf("9. %s (%d)", $@hol_name$[8], $@hol_value[8]);
+ mesf("10. %s (%d)", $@hol_name$[9], $@hol_value[9]);
+ mesf("11. %s (%d)", $@hol_name$[10], $@hol_value[10]);
+ mesf("12. %s (%d)", $@hol_name$[11], $@hol_value[11]);
+ mesf("13. %s (%d)", $@hol_name$[12], $@hol_value[12]);
+ mesf("14. %s (%d)", $@hol_name$[13], $@hol_value[13]);
+ mesf("15. %s (%d)", $@hol_name$[14], $@hol_value[14]);
+ return;
+}
+
+function script HallOfATL {
+ mes "";
+ mes l("##BHall Of Artis Legion Training Arena: TOP10##b");
+ mesf("1. %s (%d)", $@atl_name$[0], $@atl_value[0]);
+ mesf("2. %s (%d)", $@atl_name$[1], $@atl_value[1]);
+ mesf("3. %s (%d)", $@atl_name$[2], $@atl_value[2]);
+ mesf("4. %s (%d)", $@atl_name$[3], $@atl_value[3]);
+ mesf("5. %s (%d)", $@atl_name$[4], $@atl_value[4]);
+ mesf("6. %s (%d)", $@atl_name$[5], $@atl_value[5]);
+ mesf("7. %s (%d)", $@atl_name$[6], $@atl_value[6]);
+ mesf("8. %s (%d)", $@atl_name$[7], $@atl_value[7]);
+ mesf("9. %s (%d)", $@atl_name$[8], $@atl_value[8]);
+ mesf("10. %s (%d)", $@atl_name$[9], $@atl_value[9]);
+ return;
+}
+
+// Hall of AFK
+function script HallOfAFK {
+ mes "";
+ mes l("##BHall Of AFK: TOP 10##b");
+ mesf("1. %s (%dh%02dm)", $@afk_name$[0], $@afk_value[0]/1200, $@afk_value[0]%1200/60*3);
+ mesf("2. %s (%dh%02dm)", $@afk_name$[1], $@afk_value[1]/1200, $@afk_value[1]%1200/60*3);
+ mesf("3. %s (%dh%02dm)", $@afk_name$[2], $@afk_value[2]/1200, $@afk_value[2]%1200/60*3);
+ mesf("4. %s (%dh%02dm)", $@afk_name$[3], $@afk_value[3]/1200, $@afk_value[3]%1200/60*3);
+ mesf("5. %s (%dh%02dm)", $@afk_name$[4], $@afk_value[4]/1200, $@afk_value[4]%1200/60*3);
+ mesf("6. %s (%dh%02dm)", $@afk_name$[5], $@afk_value[5]/1200, $@afk_value[5]%1200/60*3);
+ mesf("7. %s (%dh%02dm)", $@afk_name$[6], $@afk_value[6]/1200, $@afk_value[6]%1200/60*3);
+ mesf("8. %s (%dh%02dm)", $@afk_name$[7], $@afk_value[7]/1200, $@afk_value[7]%1200/60*3);
+ mesf("9. %s (%dh%02dm)", $@afk_name$[8], $@afk_value[8]/1200, $@afk_value[8]%1200/60*3);
+ mesf("10. %s (%dh%02dm)", $@afk_name$[9], $@afk_value[9]/1200, $@afk_value[9]%1200/60*3);
+ return;
+}
+
+// HallOfGame()
+function script HallOfGame {
+ if ($MOST_HEROIC$)
+ mes l("World hero: %s", $MOST_HEROIC$);
+
+ if ($TREE_PLANTED)
+ mes l("Planted Trees: %s", format_number($TREE_PLANTED)); // FIXME
+
+ mes l("Players Killed in PvP: %s", format_number($PLAYERS_KILLED));
+ mes l("Monsters Killed in PvE: %s", format_number($MONSTERS_KILLED));
+ mes "";
+ .@s$=(season_direction() == WINTER ? l("Winter") : .@s$);
+ .@s$=(season_direction() == AUTUMN ? l("Autumn") : .@s$);
+ .@s$=(season_direction() == SUMMER ? l("Summer") : .@s$);
+ .@s$=(season_direction() == SPRING ? l("Spring") : .@s$);
+ mes l("Current Season: %s", .@s$);
+ // weather ; game time ; world story ; etc.
+ mes "";
+ mes l("Notable mentions and thanks for our [@@https://www.patreon.com/themanaworld|sponsors@@] for their continued support.");
+ mes "";
+ return;
+}
+
+
+// Main script handler for scoreboards
+- script @scoreboard NPC_HIDDEN,{
+ end;
+OnHour00:
+OnHour01:
+OnHour02:
+OnHour03:
+OnHour04:
+OnHour05:
+OnHour06:
+OnHour07:
+OnHour08:
+OnHour09:
+OnHour10:
+OnHour11:
+OnHour12:
+OnHour13:
+OnHour14:
+OnHour15:
+OnHour16:
+OnHour17:
+OnHour18:
+OnHour19:
+OnHour20:
+OnHour21:
+OnHour22:
+OnHour23:
+OnInit:
+ consolemes(CONSOLEMES_DEBUG, "Reloading scoreboards...");
+ .@nb = query_sql("select name, zeny from `char` ORDER BY zeny DESC LIMIT 15", $@hofortune_name$, $@hofortune_value);
+ .@nb = query_sql("select name, base_level from `char` ORDER BY base_level DESC LIMIT 15", $@hoblvl_name$, $@hoblvl_value);
+ .@nb = query_sql("select name, job_level from `char` ORDER BY job_level DESC LIMIT 15", $@hojlvl_name$, $@hojlvl_value);
+ .@nb = query_sql("select name, guild_lv from `guild` ORDER BY guild_lv DESC LIMIT 5", $@hoguild_name$, $@hoguild_value);
+ .@nb = query_sql("SELECT c.name, i.amount FROM `storage` AS i, `char` AS c WHERE i.nameid="+Acorn+" AND i.account_id=c.account_id ORDER BY i.amount DESC LIMIT 15", $@hoa_name$, $@hoa_value);
+ .@nb = query_sql("SELECT c.name, i.value FROM `char_reg_num_db` AS i, `char` AS c WHERE i.key='ATLRANK' AND i.char_id=c.char_id ORDER BY i.value DESC LIMIT 10", $@atl_name$, $@atl_value);
+ .@nb = query_sql("SELECT c.name, i.value FROM `char_reg_num_db` AS i, `char` AS c WHERE i.key='AFKING' AND i.char_id=c.char_id ORDER BY i.value DESC LIMIT 10", $@afk_name$, $@afk_value);
+ .@nb = query_sql("SELECT c.name, i.value FROM `char_reg_num_db` AS i, `char` AS c WHERE i.key='MONSTERS_KILLED' AND i.char_id=c.char_id ORDER BY i.value DESC LIMIT 15", $@hol_name$, $@hol_value);
+ consolemes(CONSOLEMES_DEBUG, "Scoreboards reloaded");
+ if (!$@SCOREBOARD_BIND) {
+ bindatcmd "scoreboard", "@scoreboard::OnCall", 0, 100, 0;
+ bindatcmd "scoreboards", "@scoreboard::OnCall", 0, 100, 0;
+ $@SCOREBOARD_BIND=true;
+ }
+ end;
+
+OnCall:
+ do {
+ clear;
+ //HallOfSponsor(true);
+ mes l("The Mana World - rEvolt");
+ mesc l("All scoreboards are updated hourly."), 1;
+ mes "";
+ select
+ l("Hall Of Fortune"),
+ l("Hall Of Base Level"),
+ l("Hall Of Job Level"),
+ l("Hall Of Guilds"),
+ l("Hall Of Lethality"),
+ l("Hall Of Acorns"),
+ l("Hall Of Artis Legion Training Arena"),
+ l("Hall Of AFK King"),
+ l("Game Statistics"),
+ l("Quit");
+ mes "";
+ switch (@menu) {
+ case 1:
+ HallOfFortune();
+ next;
+ break;
+ case 2:
+ HallOfLevel();
+ next;
+ break;
+ case 3:
+ HallOfJob();
+ next;
+ break;
+ case 4:
+ HallOfGuild();
+ next;
+ break;
+ case 5:
+ HallOfLethality();
+ next;
+ break;
+ case 6:
+ HallOfAcorns();
+ next;
+ break;
+ case 7:
+ HallOfATL();
+ next;
+ break;
+ case 8:
+ HallOfAFK();
+ next;
+ break;
+ case 9:
+ HallOfGame();
+ next;
+ break;
+ default:
+ close;
+ }
+ } while (true);
+ end;
+}
+
+
diff --git a/npc/functions/shops.txt b/npc/functions/shops.txt
new file mode 100644
index 00000000..8962997e
--- /dev/null
+++ b/npc/functions/shops.txt
@@ -0,0 +1,18 @@
+// Evol functions.
+// Author:
+// 4144
+// Jesusalva
+// Description:
+// Shops utility functions
+
+
+
+// restoreshopitem(<item nameid>, <amount>{, <price>})
+// adds back an item to the sell list if less than the specified amount
+// returns true
+
+function script restoreshopitem {
+ if (shopcount(getarg(0)) < getarg(1))
+ sellitem(getarg(0), getarg(2, -1), getarg(1));
+ return;
+}
diff --git a/npc/functions/skills.txt b/npc/functions/skills.txt
new file mode 100644
index 00000000..5273de34
--- /dev/null
+++ b/npc/functions/skills.txt
@@ -0,0 +1,20 @@
+// The Mana World scripts.
+// Author:
+// The Mana World Team
+// Description:
+// Controls script-based skills (which are rare);
+
+function script SkillInvoked {
+ // Record to database that you used the skill
+ skillInvoke[@skillId] = skillInvoke[@skillId] + 1;
+
+ // Switch though skills for additional effects
+ switch (@skillId) {
+ default:
+ // PS. I hate scripts.conf load order
+ callfunc("GetManaExp", @skillId, 1);
+ break;
+ }
+ return;
+}
+
diff --git a/npc/functions/soul-menhir.txt b/npc/functions/soul-menhir.txt
new file mode 100644
index 00000000..3d4344c9
--- /dev/null
+++ b/npc/functions/soul-menhir.txt
@@ -0,0 +1,75 @@
+// Evol scripts.
+// Author:
+// gumi
+// Jesusalva
+// Description:
+// place of power, mana refills faster when sitting nearby
+
+- script Soul Menhir NPC_HIDDEN,{
+ if (!@menhir_meditation_message)
+ {
+ dispbottom(l("You feel a strong magic aura. You want to sit near it and meditate."));
+ @menhir_meditation_message=1;
+ }
+ end;
+
+OnRefill:
+ @menhir_lock = false;
+ getmapxy(.@map$, .@x, .@y, UNITTYPE_PC);
+
+ if (.@map$ != .map$ || distance(.x, .y, .@x, .@y) > .refill_distance ||
+ !(issit()))
+ end;
+
+ heal(0, .refill_rate);
+ end;
+
+
+OnTimer500:
+ .@count = getunits(BL_PC, .@units[0], false, .map$, (.x - .refill_distance),
+ (.y - .refill_distance), (.x + .refill_distance), (.y + .refill_distance));
+
+ for (.@i = 0; .@i < .@count; ++.@i)
+ {
+ if (.@units[.@i] < 0) continue; // pre-check, just in case
+ deltimer(.name$ + "::OnRefill", .@units[.@i]);
+ if (gettimer(TIMER_COUNT, .@units[.@i], .name$ + "::OnRefill") > 0 ||
+ getvariableofpc(@menhir_lock, .@units[.@i])) {
+ continue;
+ }
+ set(getvariableofpc(@menhir_lock, .@units[.@i]), true);
+ addtimer(rand(.refill_timer), .name$ + "::OnRefill", .@units[.@i]);
+ }
+
+ initnpctimer();
+ end;
+
+OnInit:
+ // Placeholder menhir doesn't have to run
+ if (.name$ == "Soul Menhir")
+ end;
+
+ // "Next-Generation" parsing system
+ // Syntax: RATE_DISTANCE_TIMER
+ // Soul Menhir#town_rate_dist_timer
+ // example
+ // Soul Menhir#hurns_1_7_200
+ .@n$=strnpcinfo(0, "_0_0_0");
+ explode(.@ni$, .@n$, "_");
+ .refill_rate=atoi(.@ni$[1]);
+ .refill_distance=atoi(.@ni$[2]);
+ .refill_timer=atoi(.@ni$[3]);
+
+ // number of SP to give every refill
+ if (!.refill_rate)
+ .refill_rate = 1;
+ // max distance
+ if (.refill_distance < 0)
+ .refill_distance = 7;
+ // wait rand(X) ms before refill
+ if (.refill_timer < 1)
+ .refill_timer = 200;
+
+ initnpctimer();
+ end;
+}
diff --git a/npc/functions/spotlight.txt b/npc/functions/spotlight.txt
new file mode 100644
index 00000000..219d3a31
--- /dev/null
+++ b/npc/functions/spotlight.txt
@@ -0,0 +1,92 @@
+// Evol functions.
+// Author:
+// Jesusalva
+// Micksha
+// Description:
+// Update spotlight on caves
+// Variables:
+// 2 - the darkest mask
+// 4 - the average mask
+// 8 - the lightest mask
+
+// forced_update - if set to true, will ignore if the map is known as valid
+// (required for instance maps)
+// updateSpotlight ( {forced_update} )
+function script updateSpotlight {
+ // A small delay of 80 ms in case player is changing map
+ // It will be cast twice when switching caves. This sleep prevents obscure bugs.
+ sleep2(80);
+
+ getmapxy(.@m$, .@x, .@y, 0);
+
+ // Is your map valid (or is the check skipped)
+ if (!getarg(0,false))
+ {
+ if (strpos(getmapname(), "-3-") < 0)
+ return;
+ }
+
+ // Retrieve default map masks
+ .@ms=getmapmask(.@m$);
+
+ // Which equipments provide bonuses?
+ setarray .@b_head, CandleHelmet;
+ setarray .@b_weapon, ManaTorch, TrainingWand, Torch;
+
+ // Calc your lighting score (it should NOT start on zero)
+ .@score=1;
+ if (array_find(.@b_head, getequipid(EQI_HEAD_TOP)) >= 0)
+ .@score+=1;
+ if (array_find(.@b_weapon, getequipid(EQI_HAND_R)) >= 0)
+ .@score+=1;
+ // TODO: Lighting scrolls
+
+ //debugmes "Score: %d", .@score;
+ //debugmes "Equips: %d and %d", getequipid(EQI_HEAD_TOP), getequipid(EQI_HAND_R);
+ //debugmes "Headvalue: %d", .@b_head[0];
+ //debugmes "Weappnvalue: %d, %d, %d", .@b_weapon[0], .@b_weapon[1], .@b_weapon[2];
+ // Sanitize score
+ .@score=min(3, .@score);
+
+ // Calculate and send new map mask
+ .@ms=.@ms|(2**.@score);
+ sendmapmask(.@ms);
+ return;
+}
+
+// MAIN FUNCTION - DO NOT REMOVE
+// Every NPC will be duplicating this one
+001-3-0,0,0,0 script #SpotlightMaster NPC_HIDDEN,0,0,{
+OnTouch:
+ updateSpotlight(true);
+ end;
+}
+
+
+// I'm too lazy to do this in different files and in the right spot.....
+
+// npc/001-3-0/_warps.txt
+001-3-0,196,35,0 duplicate(#SpotlightMaster) #SPOT001-3-0_196_35 NPC_HIDDEN,2,2
+001-3-0,172,41,0 duplicate(#SpotlightMaster) #SPOT001-3-0_172_41 NPC_HIDDEN,2,2
+001-3-0,162,40,0 duplicate(#SpotlightMaster) #SPOT001-3-0_162_40 NPC_HIDDEN,2,2
+001-3-0,198,60,0 duplicate(#SpotlightMaster) #SPOT001-3-0_198_60 NPC_HIDDEN,2,2
+001-3-0,152,55,0 duplicate(#SpotlightMaster) #SPOT001-3-0_152_55 NPC_HIDDEN,2,2
+001-3-0,85,130,0 duplicate(#SpotlightMaster) #SPOT001-3-0_85_130 NPC_HIDDEN,2,2
+
+// npc/001-3-1/_warps.txt
+001-3-1,24,58,0 duplicate(#SpotlightMaster) #SPOT001-3-1_24_58 NPC_HIDDEN,2,2
+001-3-1,35,59,0 duplicate(#SpotlightMaster) #SPOT001-3-1_35_59 NPC_HIDDEN,2,2
+//001-3-1,30,19,0 duplicate(#SpotlightMaster) #SPOT001-3-1_30_19 NPC_HIDDEN,2,2
+
+// npc/001-3-2/_warps.txt
+001-3-2,30,117,0 duplicate(#SpotlightMaster) #SPOT001-3-2_30_117 NPC_HIDDEN,2,2
+
+// npc/008-3-0/_warps.txt
+008-3-0,130,113,0 duplicate(#SpotlightMaster) #SPOT008-3-0_130_113 NPC_HIDDEN,2,2
+
+// npc/008-3-1/_warps.txt
+008-3-1,34,34,0 duplicate(#SpotlightMaster) #SPOT008-3-1_34_34 NPC_HIDDEN,2,2
+
+// npc/008-3-2/_warps.txt
+008-3-2,175,18,0 duplicate(#SpotlightMaster) #SPOT008-3-2_175_18 NPC_HIDDEN,2,2
+
diff --git a/npc/functions/string.txt b/npc/functions/string.txt
new file mode 100644
index 00000000..ef2e4c2a
--- /dev/null
+++ b/npc/functions/string.txt
@@ -0,0 +1,196 @@
+// safe string manipulation functions
+// ** does not require PCRE
+
+
+// str(<int>)
+// returns whatever is passed, converted to string
+
+function script str {
+ return "" + getarg(0);
+}
+
+
+
+// startswith("<string>", "<search>")
+// returns true if <string> begins with <search>
+
+function script startswith {
+ return substr(getarg(0), 0, getstrlen(getarg(1)) - 1) == getarg(1);
+}
+
+
+
+// endswith("<string>", "<search>")
+// returns true if <string> ends with <search>
+
+function script endswith {
+ .@t = getstrlen(getarg(0)); // total length
+ .@n = getstrlen(getarg(1)); // substring length
+ return substr(getarg(0), .@t - .@n, .@t - 1) == getarg(1);
+}
+
+
+
+// capitalize("<string>")
+// returns <string> with its first letter capitalized
+
+function script capitalize {
+ return setchar(getarg(0), strtoupper(charat(getarg(0), 0)), 0);
+}
+
+
+
+// titlecase("<string>" {, "<delimiter>" {, <camel>}})
+// returns <string> with the first letter of each word capitalized
+// if <camel> is true, the string is joined in a camelCase fashion
+
+function script titlecase {
+ .@delimiter$ = getarg(1, " ");
+ .@c = getarg(2, 0);
+ explode(.@words$, getarg(0), .@delimiter$);
+
+ for (.@i = (.@c ? 1 : 0); .@i < 255; ++.@i)
+ {
+ if (.@words$[.@i] == "")
+ {
+ break;
+ }
+
+ .@words$[.@i] = setchar(.@words$[.@i], strtoupper(charat(.@words$[.@i], 0)), 0);
+ }
+
+ return implode(.@words$, (.@c ? "" : .@delimiter$));
+}
+
+
+
+// camelcase("<string" {, "<delimiter>"})
+
+function script camelcase {
+ return titlecase(getarg(0), getarg(1, " "), true);
+}
+
+
+
+// zfill("<string>" {, <width> {, "<padding>"}})
+// returns <string> padded to the left with <padding> up to width
+
+function script zfill {
+ .@str$ = getarg(0);
+ .@width = getarg(1, 8);
+ .@padding$ = getarg(2, "0");
+
+ for (.@s = getstrlen(.@str$); .@s < .@width; ++.@s)
+ {
+ .@str$ = .@padding$ + .@str$;
+ }
+
+ return .@str$;
+}
+
+
+
+// format_number(<integer> {, "<separator>"})
+// formats a number properly
+
+function script format_number {
+ .@number$ = str(getarg(0));
+ .@len = getstrlen(.@number$);
+ .@separator$ = getarg(1, ",");
+
+ if (getargcount() < 2 && playerattached()) {
+ // get from user language
+ switch (Lang) {
+ case LANG_FR: .@separator$ = " "; break; // French
+ //case LANG_BR: .@separator$ = "."; break; // Portuguese
+ default: .@separator$ = ","; // English (default)
+ }
+ }
+
+ for (.@i = .@len - 3; .@i > 0; .@i -= 3) {
+ .@number$ = insertchar(.@number$, .@separator$, .@i);
+ }
+
+ return .@number$;
+}
+
+
+
+// strip("<string>")
+// removes spaces at the start and end
+
+function script strip {
+ .@s$ = getarg(0);
+ if (.@s$ == "") {
+ return "";
+ }
+ .@start = 0;
+ .@end = getstrlen(.@s$) - 1;
+ for (.@i = .@start; .@i < .@end; .@i++)
+ {
+ if (charat(.@s$, .@i) != " ") {
+ break;
+ } else {
+ .@start++;
+ }
+ }
+ for (.@i = .@end; .@i >= .@start; .@i--)
+ {
+ if (charat(.@s$, .@i) != " ") {
+ break;
+ } else {
+ .@end--;
+ }
+ }
+ return substr(.@s$, .@start, .@end);
+}
+
+
+
+// reverse("<string>")
+// returns <string> reversed
+
+function script reverse {
+ .@str$ = getarg(0);
+ .@len = getstrlen(.@str$);
+
+ for (.@i = 0; .@i < (.@len / 2); ++.@i) {
+ .@tmp$ = charat(.@str$, .@i);
+ .@str$ = setchar(.@str$, charat(.@str$, (.@len - 1 - .@i)), .@i); // a <= b
+ .@str$ = setchar(.@str$, .@tmp$, (.@len - 1 - .@i)); // b <= a
+ }
+
+ return .@str$;
+}
+
+
+
+// repeat("<string>", <multiplier>)
+// repeats <string> many times and returns it
+
+function script repeat {
+ .@mul = getarg(1);
+
+ for (.@i = 0; .@i < .@mul; ++.@i) {
+ .@str$ += getarg(0);
+ }
+
+ return .@str$;
+}
+
+
+
+// shuffle("<string>")
+// returns <string> shuffled
+
+function script shuffle {
+ .@str$ = getarg(0);
+
+ for (.@len = getstrlen(.@str$); .@len > 0; --.@len) {
+ .@rnd = rand(.@len);
+ .@out$ += charat(.@str$, .@rnd);
+ .@str$ = delchar(.@str$, .@rnd);
+ }
+
+ return .@out$;
+}
diff --git a/npc/functions/time.txt b/npc/functions/time.txt
new file mode 100644
index 00000000..8376d6a0
--- /dev/null
+++ b/npc/functions/time.txt
@@ -0,0 +1,108 @@
+function script now {
+ return gettimetick(2);
+}
+
+
+function script time_from_ms {
+ return now() + (getarg(0) / 1000);
+}
+
+function script time_from_seconds {
+ return now() + getarg(0);
+}
+
+function script time_from_minutes {
+ return now() + (getarg(0) * 60);
+}
+
+function script time_from_hours {
+ return now() + (getarg(0) * 3600);
+}
+
+function script time_from_days {
+ return now() + (getarg(0) * 86400);
+}
+
+
+// FuzzyTime(<unix timestamp>{, <options>{, <precision>}})
+// gives time in a human-readable format
+//
+// <options> is bitmasked:
+// 1 do not show "ago" when in past
+// 2 do not show "in" when in the future (default)
+// 4 show "from now" instead of "in" when in the future
+//
+// <precision> is the number of units to show,
+// do not exceed 99 (default is 2)
+
+function script FuzzyTime {
+ .@future = getarg(0, now());
+ .@options = getarg(1, 2);
+ .@precision = getarg(2, 2);
+ .@diff = (.@future - now());
+
+ // check if in the past, or in the future
+ if (.@diff < 0) {
+ .@diff *= -1;
+ .@past = true;
+ }
+
+ .@diff = max(1, .@diff);
+
+ if (.@diff >= 31536000) {
+ .@years = (.@diff / 31536000);
+ .@diff = (++.@s == .@precision ? 0 : (.@diff % 31536000));
+ .@ret$ += sprintf("%d %s", .@years, (.@years > 1 ? "years" : "year"));
+ }
+
+ if (.@diff >= 86400) {
+ .@days = (.@diff / 86400);
+ .@diff = (++.@s == .@precision ? 0 : (.@diff % 86400));
+
+ if (.@s > 1) {
+ .@ret$ += (.@diff > 0 ? ", " : " and ");
+ }
+
+ .@ret$ += sprintf("%d %s", .@days, (.@days > 1 ? "days" : "day"));
+ }
+
+ if (.@diff >= 3600) {
+ .@hours = (.@diff / 3600);
+ .@diff = (++.@s == .@precision ? 0 : (.@diff % 3600));
+
+ if (.@s > 1) {
+ .@ret$ += (.@diff > 0 ? ", " : (.@s >= 3 ? ", " : " ") + "and ");
+ }
+
+ .@ret$ += sprintf("%d %s", .@hours, (.@hours > 1 ? "hours" : "hour"));
+ }
+
+ if (.@diff >= 60) {
+ .@minutes = (.@diff / 60);
+ .@diff = (++.@s == .@precision ? 0 : (.@diff % 60));
+
+ if (.@s > 1) {
+ .@ret$ += (.@diff > 0 ? ", " : (.@s >= 3 ? ", " : " ") + "and ");
+ }
+
+ .@ret$ += sprintf("%d %s", .@minutes, (.@minutes > 1 ? "minutes" : "minute"));
+ }
+
+ if (.@diff >= 1) {
+ if (++.@s > 1) {
+ .@ret$ += (.@s >= 3 ? ", " : " ") + "and ";
+ }
+
+ .@ret$ += sprintf("%d %s", .@diff, (.@diff > 1 ? "seconds" : "second"));
+ }
+
+ if (.@past && !(.@options & 1)) {
+ .@ret$ += " ago";
+ }
+
+ if (!(.@past) && !(.@options & 2)) {
+ .@ret$ = ((.@options & 4) ? sprintf("%s from now", .@ret$) : sprintf("in %s", .@ret$));
+ }
+
+ return .@ret$;
+}
diff --git a/npc/functions/timer.txt b/npc/functions/timer.txt
new file mode 100644
index 00000000..fbfec3fd
--- /dev/null
+++ b/npc/functions/timer.txt
@@ -0,0 +1,63 @@
+// addtimer2(<tick>, "<npc>::<event>")
+function script addtimer2 {
+ deltimer(getarg(1));
+ addtimer(getarg(0), getarg(1));
+ return;
+}
+
+// areatimer("<map>", <x1>, <y1>, <x2>, <y2>, <tick>, "<npc>::<event>")
+function script areatimer {
+ .@c = getunits(BL_PC, .@players, false, getarg(0), getarg(1), getarg(2), getarg(3), getarg(4));
+ for (.@i = 0; .@i < .@c; .@i++) {
+ addtimer(getarg(5), getarg(6), .@players[.@i]);
+ }
+ return .@i;
+}
+
+// areadeltimer("<map>", <x1>, <y1>, <x2>, <y2>, "<npc>::<event>")
+function script areadeltimer {
+ .@c = getunits(BL_PC, .@players, false, getarg(0), getarg(1), getarg(2), getarg(3), getarg(4));
+ for (.@i = 0; .@i < .@c; .@i++) {
+ deltimer(getarg(5), .@players[.@i]);
+ }
+ return .@i;
+}
+
+// areatimer2("<map>", <x1>, <y1>, <x2>, <y2>, <tick>, "<npc>::<event>")
+function script areatimer2 {
+ .@c = getunits(BL_PC, .@players, false, getarg(0), getarg(1), getarg(2), getarg(3), getarg(4));
+ for (.@i = 0; .@i < .@c; .@i++) {
+ deltimer(getarg(6), .@players[.@i]);
+ addtimer(getarg(5), getarg(6), .@players[.@i]);
+ }
+ return .@i;
+}
+
+
+// maptimer("<map>", <tick>, "<npc>::<event>")
+function script maptimer {
+ .@c = getunits(BL_PC, .@players, false, getarg(0));
+ for (.@i = 0; .@i < .@c; .@i++) {
+ addtimer(getarg(1), getarg(2), .@players[.@i]);
+ }
+ return .@i;
+}
+
+// maptimer2("<map>", <tick>, "<npc>::<event>")
+function script maptimer2 {
+ .@c = getunits(BL_PC, .@players, false, getarg(0));
+ for (.@i = 0; .@i < .@c; .@i++) {
+ deltimer(getarg(2), .@players[.@i]);
+ addtimer(getarg(1), getarg(2), .@players[.@i]);
+ }
+ return .@i;
+}
+
+// mapdeltimer("<map>", "<npc>::<event>")
+function script mapdeltimer {
+ .@c = getunits(BL_PC, .@players, false, getarg(0));
+ for (.@i = 0; .@i < .@c; .@i++) {
+ deltimer(getarg(1), .@players[.@i]);
+ }
+ return .@i;
+}
diff --git a/npc/functions/treasure.txt b/npc/functions/treasure.txt
new file mode 100644
index 00000000..785dd4a0
--- /dev/null
+++ b/npc/functions/treasure.txt
@@ -0,0 +1,134 @@
+// Moubootaur Legends functions.
+// Author:
+// Jesusalva
+// Description:
+// Random Treasure Box Utils
+
+function script TreasureBox {
+ .@id=getnpcid();
+ if (RNGTREASURE_DATE[.@id] > gettimetick(2)) {
+ mesc l("The chest is unlocked and empty.");
+ close;
+ }
+
+ mesc l("Open the chest?");
+ mesc l("Cost: 1 %s", getitemlink(TreasureKey)), 1;
+ if (!countitem(TreasureKey))
+ close;
+ next;
+ if (askyesno() == ASK_NO)
+ close;
+
+ delitem TreasureKey, 1;
+ mesc l("You open the chest!");
+ RNGTREASURE_DATE[.@id]=gettimetick(2)+CHEST_WAITTIME; // Minimum 15 minutes
+
+ .@empty=getvariableofnpc(.empty, strnpcinfo(0));
+ if (!.@empty) {
+ TREASURE_OPEN=TREASURE_OPEN+1;
+ .@t=TREASURE_OPEN;
+ .@r=rand(0,10000)-(readbattleparam(getcharid(3), UDT_LUK)*2);
+
+ // Select treasure list
+ // You're warranted a rare (5%) every 25 open chests
+ // There's also uncommons (20%) and commons (75%)
+ if (.@t == 1)
+ .@loot=WoodenBow;
+ else if (.@t % 25 == 0 || .@r < 500) // Rare: 5%
+ .@loot=any(AtroposMixture, ElixirOfLife, BigHealing, BigMana, DeathPotion, MagicFeather);
+ else if (.@r < 2500) // Uncommon: 20%
+ .@loot=any(FatesPotion, ClothoLiquor, LachesisBrew, RedPlushWine, TreasureMap, MediumHealing, MediumMana);
+ else // Common: 75%
+ .@loot=any(Bread, Fungus, Cheese, Aquada, Croconut, PiberriesInfusion, Carrot, SmallHealing, SmallMana);
+
+
+ inventoryplace .@loot, 1;
+ mesc l("You find %s inside!", getitemlink(.@loot));
+ getitem .@loot, 1;
+ } else {
+ mesc l("You find %s inside!", l("nothing"));
+ }
+ return;
+}
+
+// Animation code by Evol Team
+// 4144, gumi, Hal9000, Reid
+// (Random) Treasure Chest
+// Authored by Jesusalva
+// Regenerates every 6 hours
+001-3-0,0,0,0 script #chest_001-3-0 NPC_CHEST,{
+ /*
+ // Extract the map name - Seems unused
+ explode(.@ni$, .name$, "_");
+ .@map$=.@ni$[1];
+ //if (.@map$ == "") debugmes "Error";
+ */
+
+ // Conditionals
+ if (!.busy) {
+ TreasureBox();
+
+ specialeffect(.dir == 0 ? 24 : 25, AREA, getnpcid()); // closed ? opening : closing
+ .dir = .dir == 0 ? 2 : 6; // closed ? opening : closing
+ .busy = true; // lock until available again
+ initnpctimer;
+ } else {
+ mesc l("Someone looted this treasure box already...");
+ }
+ close;
+
+OnTimer160:
+ .dir = .dir == 6 ? 0 : 4; // closing ? closed : open
+ end;
+
+OnTimer500:
+ // It's closed: Make available and stop timer
+ if (.dir == 0) {
+ .busy = false;
+ stopnpctimer;
+ }
+ end;
+
+// Autoclose
+OnTimer60000:
+ .dir = 6; // closing
+ specialeffect(25, AREA, getnpcid()); // closing
+ setnpctimer 0;
+ end;
+
+OnInit:
+ .busy = false;
+ .distance = 2;
+
+OnClock0156:
+OnClock0756:
+OnClock1356:
+OnClock1956:
+ // Try to warp randomly to a walkable spot, up to 20 attempts
+ // Otherwise, it'll stay where it already is (but will close and refill).
+ .@e=0; .@x=0; .@y=0;
+ while (!checkcell(.map$, .@x, .@y, cell_chkpass))
+ {
+ if (.@e == 20) {
+ .@x=.x;
+ .@y=.y;
+ break;
+ }
+ // Remember the +20 -20 margin adjustment
+ .@x = rand2(20, getmapinfo(MAPINFO_SIZE_X, .map$)-20);
+ .@y = rand2(20, getmapinfo(MAPINFO_SIZE_X, .map$)-20);
+ ++.@e;
+ }
+ .busy=false;
+ movenpc .name$, .@x, .@y, 0;
+ end;
+}
+
+// Lets bring some treasure to The Mana World
+008-3-4,0,0,0 duplicate(#chest_001-3-0) #chest_008-3-4 NPC_TREASURE
+008-3-5,0,0,0 duplicate(#chest_001-3-0) #chest_008-3-5 NPC_TREASURE
+008-3-6,0,0,0 duplicate(#chest_001-3-0) #chest_008-3-6 NPC_TREASURE
+
+012-3-1,0,0,0 duplicate(#chest_001-3-0) #chest_012-3-1 NPC_TREASURE
+012-3-3,0,0,0 duplicate(#chest_001-3-0) #chest_012-3-3 NPC_TREASURE
+
diff --git a/npc/functions/util.txt b/npc/functions/util.txt
new file mode 100644
index 00000000..cedd4202
--- /dev/null
+++ b/npc/functions/util.txt
@@ -0,0 +1,102 @@
+// Evol functions.
+// Authors:
+// Jesusalva
+// Reid
+// Description:
+// Util functions
+
+
+// season_direction({day, month})
+// returns the direction that represents our current season (approximation)
+// Note: You may also use WINTER/SPRING/SUMMER/AUTUMN constants for scripts
+// where the direction is not important, but the season is. (Readability)
+// DOWN: Winter, 21/12 WINTER
+// DOWNLEFT: Spring, 20/03 SPRING
+// LEFT: Summer, 21/06 SUMMER
+// UPLEFT: Autumn, 22/09 AUTUMN
+
+function script season_direction {
+ .@current_month = getarg(1, gettime(GETTIME_MONTH));
+
+ if (.@current_month % 3 == 0)
+ {
+ .@current_day = getarg(0, gettime(GETTIME_DAYOFMONTH));
+
+ switch (.@current_month)
+ {
+ case MARCH: .@season_day = 20; break;
+ case JUNE: .@season_day = 21; break;
+ case SEPTEMBER: .@season_day = 22; break;
+ case DECEMBER: .@season_day = 21; break;
+ default: break;
+ }
+
+ .@is_after_season_day = .@current_day >= .@season_day ? 0 : -1;
+ }
+
+ return (.@current_month / 3 + .@is_after_season_day) % 4;
+}
+
+// This is part of Jesusalva script toolkit to make his life easier when writing
+// quests. Many of these are actually redundant functions.
+
+// Four different flavours of setq() to quickly preserve old values
+function script setq1 {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getarg(1), getq2(getarg(0)), getq3(getarg(0)), getqtime(getarg(0));
+ return;
+}
+
+function script setq2 {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getq(getarg(0)), getarg(1), getq3(getarg(0)), getqtime(getarg(0));
+ return;
+}
+
+function script setq3 {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getq(getarg(0)), getq2(getarg(0)), getarg(1), getqtime(getarg(0));
+ return;
+}
+
+function script setqtime {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getq(getarg(0)), getq2(getarg(0)), getq3(getarg(0)), getarg(1);
+ return;
+}
+
+// gettimeparam(GETTIME_X)
+// Returns the number of seconds/minutes/hours/days/months/years since 01/01/1970
+// This is for truly daily quests, which doesn't imposes a timed wait in hours
+function script gettimeparam {
+ .@p=getarg(0, GETTIME_MINUTE);
+
+ // Seconds (same as gettimetick(2) - use that instead)
+ .@t=gettimetick(2);
+ if (.@p == GETTIME_SECOND)
+ return .@t;
+
+ // Minutes (default)
+ .@t=.@t/60;
+ if (.@p == GETTIME_MINUTE)
+ return .@t;
+
+ // Hours
+ .@t=.@t/60;
+ if (.@p == GETTIME_HOUR)
+ return .@t;
+
+ // Days
+ .@t=.@t/24;
+ if (.@p == GETTIME_DAYOFMONTH)
+ return .@t;
+
+ // Months (estimative)
+ .@t=.@t/30;
+ if (.@p == GETTIME_MONTH)
+ return .@t;
+
+ // Years (estimative, unused, fallback)
+ .@t=.@t/12;
+ return .@t;
+}
diff --git a/npc/functions/vault.txt b/npc/functions/vault.txt
new file mode 100644
index 00000000..1cfe7c99
--- /dev/null
+++ b/npc/functions/vault.txt
@@ -0,0 +1,98 @@
+// TODO: create a Vault hercules plugin for native support
+
+// NOTE: no script other than the functions in this file should EVER access
+// ##VAULT[] or the vault-bound variables
+
+/**
+ * Gets the Vault account ID of the provided or attached player.
+ * If the server does not use Vault, it returns a virtual Vault ID.
+ *
+ * Example:
+ * getvaultid("player name");
+ *
+ * @param 0? - char name / account id (defaults to attached player)
+ * @return the Vault ID
+ */
+function script getvaultid {
+ if (SERVER_USES_VAULT) {
+ // we dereference the variable to avoid accidental assignment
+ return 0+ getvariableofpc(##VAULT[0], nameid2id(getarg(0, "")));
+ } else {
+ return nameid2id(getarg(0, ""));
+ }
+}
+
+/**
+ * gets a (fake) vault account-bound variable.
+ * right now these are map-server global variables so they should be used
+ * sparingly
+ *
+ * Example:
+ * set(getvaultvar(VAR$), "foo bar");
+ *
+ * @param 0 - a variable name without prefix
+ * @param 1? - char name / account id (defaults to attached player)
+ * @return a reference to the variable
+ */
+function script getvaultvar {
+ if ((getdatatype(getarg(0)) & DATATYPE_VAR) == 0) {
+ consolemes(CONSOLEMES_ERROR, "getvaultvar: first argument should be a variable");
+ end;
+ }
+
+ .@var$ = data_to_string(getarg(0));
+
+ if (charat(.@var$, 0) == "." || charat(.@var$, 0) == "@" ||
+ charat(.@var$, 0) == "$" || charat(.@var$, 0) == "#") {
+ consolemes(CONSOLEMES_ERROR, "getvaultvar: the variable must be unprefixed");
+ end;
+ }
+
+ if (SERVER_USES_VAULT) {
+ .@vault = getvaultid(getarg(1, ""));
+ return getd(sprintf("$VAULT_%s[%i]", .@var$, .@vault));
+ } else {
+ return getvariableofpc(getd(sprintf("##%s", .@var$)), nameid2id(getarg(1, "")));
+ }
+}
+
+/**
+ * sets a (fake) vault account-bound variable.
+ * right now these are map-server global variables so they should be used
+ * sparingly
+ *
+ * Example:
+ * setvaultvar(FOO$, "bar");
+ *
+ * @param 0 - a variable name without prefix
+ * @param 1 - the value to set
+ * @param 2? - char name / account id (defaults to attached player)
+ * @return a reference to the variable
+ */
+function script setvaultvar {
+ return set(getvaultvar(getarg(0), getarg(2, "")), getarg(1));
+}
+
+/**
+ * handles Vault hooks on player login
+ */
+- script VaultHandler NPC_HIDDEN,{
+ public function OnDualLogin {
+ .@toKick$ = strcharinfo(PC_NAME, "", getarg(0, 0));
+
+ if (.@toKick$ != "") {
+ .@msg$ = sprintf("Kicking player %s (Vault dual-login)", .@toKick$);
+ consolemes(CONSOLEMES_INFO, .@msg$); // log this
+ dispbottom(.@msg$); // tell the player
+
+ return kick(.@toKick$, 2); // reason 2 is dual-login
+ }
+
+ return false;
+ }
+
+OnInit:
+ if (SERVER_USES_VAULT) {
+ "playerCache"::addVaultHandler("OnDualLogin");
+ }
+}
diff --git a/npc/functions/villagertalk.txt b/npc/functions/villagertalk.txt
new file mode 100644
index 00000000..371a9f20
--- /dev/null
+++ b/npc/functions/villagertalk.txt
@@ -0,0 +1,53 @@
+// Evol functions.
+// Authors:
+// Akko Teru
+// Qwerty Dragon
+// Reid
+// Description:
+// Tell a random sentence. || There ought to be a law!
+
+function script villagertalk {
+
+ function darn_or_smile
+ {
+ .@darn = rand(42);
+
+ if (.@darn < 26)
+ {
+ emotion E_JOY;
+ hello;
+ }
+ else if (.@darn > 26)
+ {
+ emotion E_LOOKAWAY;
+ goodbye;
+ }
+ else
+ {
+ npctalkonce(l("Stop it!"));
+ }
+
+ return;
+ }
+
+ switch (rand(4))
+ {
+ case 0:
+ darn_or_smile();
+ break;
+ case 1:
+ npctalkonce(l("It is a sunny day, don't you think?"));
+ break;
+ case 2:
+ npctalkonce(l("Go fly a kite."));
+ break;
+ case 3:
+ npctalkonce(l("I just want to live my life in peace."));
+ break;
+ default:
+ emotion E_HAPPY;
+ break;
+ }
+
+ return;
+}
diff --git a/npc/functions/warp.txt b/npc/functions/warp.txt
new file mode 100644
index 00000000..46c390ad
--- /dev/null
+++ b/npc/functions/warp.txt
@@ -0,0 +1,58 @@
+// Evol functions.
+// Authors:
+// gumi
+
+
+
+// map_exists
+// self-explanatory
+
+function script map_exists {
+ return getmapinfo(MAPINFO_ID, getarg(0)) >= 0;
+}
+
+
+
+// slide_or_warp
+// Slides the player instead of warping, when possible.
+// usage:
+// slide_or_warp({<aid>});
+// slide_or_warp(<x>, <y>{, <aid>});
+// slide_or_warp("<map>", <x>, <y>{, <aid>});
+
+function script slide_or_warp {
+ if (getargcount() <= 1) {
+ .@aid = getarg(1, 0);
+ } else {
+ if (getargcount() >= 3 && getdatatype(getarg(0)) & DATATYPE_STR) {
+ .@map$ = getarg(0);
+ .@x = getarg(1);
+ .@y = getarg(2);
+ .@aid = getarg(3, 0);
+ } else {
+ .@x = getarg(0);
+ .@y = getarg(1);
+ .@aid = getarg(2, 0);
+ }
+ }
+
+ if (!isloggedin(.@aid)) {
+ if ((.@aid = playerattached()) == 0) {
+ consolemes(CONSOLEMES_DEBUG, "slide_or_warp: no player attached!");
+ return false;
+ }
+ }
+
+ getmapxy(.@pc_map$, .@pc_x, .@pc_y, UNITTYPE_PC, .@aid); // get char location
+ .@cid = getcharid(CHAR_ID_CHAR, strcharinfo(PC_NAME, .@aid)); // FIXME: [Hercules] make it so you can pass account id directly to getcharid
+
+ if (getargcount() < 1) {
+ warpchar(.@pc_map$, .@pc_x, .@pc_y, .@cid); // no arguments, just refresh
+ } else if (.@map$ == .@pc_map$ && (.@pc_x != .@x || .@pc_y != .@y)) {
+ slide(.@x, .@y); // same map, slide instead of full warp
+ // FIXME: make slide take GID as optional arg
+ } else {
+ warpchar(.@map$, .@x, .@y, .@cid); // different map, warp to given location
+ }
+ return true;
+}
diff --git a/npc/items/cookie.txt b/npc/items/cookie.txt
new file mode 100644
index 00000000..e451e844
--- /dev/null
+++ b/npc/items/cookie.txt
@@ -0,0 +1,22 @@
+// Evol script.
+// Author:
+// Jesusalva
+// Reid (?)
+// Description:
+// Prevents cookie from being used for too long
+
+function script UnequipCookie {
+ if (getequipid(EQI_HEAD_MID) == DeliciousCookie)
+ unequip(EQI_HEAD_MID);
+ return;
+}
+
+- script #DeliciousCookie NPC_HIDDEN,{
+ end;
+
+OnUnequip:
+ UnequipCookie();
+ end;
+
+}
+
diff --git a/npc/items/croconut.txt b/npc/items/croconut.txt
new file mode 100644
index 00000000..8e54971d
--- /dev/null
+++ b/npc/items/croconut.txt
@@ -0,0 +1,72 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Allows to cut a Croconut in multiple parts.
+//
+// Possible choices for L_Weapon:
+// rif(countitem(35xx), l(getitemname(xx))), L_Weak,
+// rif(countitem(35yy), l(getitemname(yy))), L_Good,
+
+000-2-1,0,0,0 script Croconut NPC_HIDDEN,{
+ close;
+
+OnUse:
+ mesn "Narrator";
+ mesc(l("Do you want to cut this @@?", getitemlink(Croconut)), 9);
+ next;
+
+ menu
+ l("Yes."), L_Weapon,
+ l("No."), -;
+
+ getitem Croconut, 1;
+ close;
+
+L_Weapon:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Which of your weapons do you want to use in order to cut this @@?", getitemlink(Croconut)), 9);
+ next;
+
+ menu
+ rif(countitem(Knife) > 0, l(getitemname(Knife))), L_Weak,
+ rif(countitem(PiouSlayer) > 0, l(getitemname(PiouSlayer))), L_Weak,
+ rif(countitem(TrainingGladius) > 0, l(getitemname(TrainingGladius))), L_Good,
+ rif(countitem(WoodenSword) > 0, l(getitemname(WoodenSword))), L_Weak,
+ rif(countitem(ArtisBacksword) > 0, l(getitemname(ArtisBacksword))), L_Good,
+ l("Bare Hands"), -;
+
+L_TooWeak:
+ mes "";
+ mesn "Narrator";
+
+ .@q = rand(5);
+ if (.@q == 0) goto L_TooWeakLost;
+ if ( (.@q == 1) || (.@q == 2) ) goto L_TooWeakFail;
+ if ( (.@q == 3) || (.@q == 4) || (.@q == 5) ) goto L_Weak;
+
+L_TooWeakLost:
+ mesc(l("You hit too hard with your fist, you destroyed your @@.", getitemlink(Croconut)), 9);
+
+ close;
+
+L_TooWeakFail:
+ mesc(l("Your hands are too weak, you did not succeed in opening this @@.", getitemlink(Croconut)), 9);
+
+ getitem Croconut, 1;
+ close;
+
+L_Weak:
+ mesc(l("You opened the @@ in two parts, but you crushed one of them.", getitemlink(Croconut)), 9);
+
+ getitem HalfCroconut, 1;
+ close;
+
+L_Good:
+ mesc(l("You perfectly cut your @@ into two edible parts.", getitemlink(Croconut)), 9);
+
+ getitem HalfCroconut, 2;
+ close;
+}
diff --git a/npc/items/gift.txt b/npc/items/gift.txt
new file mode 100644
index 00000000..be77bdfa
--- /dev/null
+++ b/npc/items/gift.txt
@@ -0,0 +1,35 @@
+// Referral Gifts
+// Rebased from Moubootaur Legends
+// Author:
+// Jesusalva
+
+function script OpenFriendGift {
+ if (BaseLevel < 5) {
+ dispbottom(l("You must reach level 5 to open this gift."));
+ getitembound(FriendGift, 1, 1);
+ return;
+ }
+
+ getitem(Acorn, 1); // FIXME: placeholder
+ //getitem(EventCoin, rand(1,3));
+
+ .@refVault = bitwise_get(getvaultvar(REFERRAL_PROG), 0x00FFFFFF, 0);
+ .@refChar = "playerCache"::vault2char(.@refVault);
+ .@refName$ = "playerCache"::char2name(.@refChar);
+
+ //$REFERRAL_IDS[.@refVault] += 1;
+ // ^ this doesn't seem to serve any purpose...
+ // if we want to keep track of how many accounts someone referred it
+ // should be something like:
+ // .@count = getvaultvar(REFERRAL_COUNT, .@refVault);
+ // setvaultvar(REFERRAL_COUNT, .@count + 1, .@refVault);
+
+ dispbottom(l("Oooh, a gift from %s!", .@refName$));
+ rodex_sendmail(.@refChar, "TMW Team",
+ "Invite Accepted",
+ sprintf("%s accepted your invitation and reached level 5!\n"
+ "As they get stronger, more rewards will be sent to you!",
+ strcharinfo(PC_NAME)),
+ rand(50, 150));
+ return;
+}
diff --git a/npc/items/master_skillbook.txt b/npc/items/master_skillbook.txt
new file mode 100644
index 00000000..007125cc
--- /dev/null
+++ b/npc/items/master_skillbook.txt
@@ -0,0 +1,164 @@
+// The Mana World script.
+// Author:
+// Jesusalva
+// Elvano
+// Description:
+// Contains master skills which can only be learnt after killing boss
+// See also: https://forums.themanaworld.org/viewtopic.php?f=2&t=19918
+// Notes:
+// Not exactly as Elvano proposal. I actually care for restrictions you know...
+// Variables:
+// PERMANENT:
+// MASTERBOOK_PAGES - How many pages your Master Book have.
+// Defaults to zero, so you can't @item it.
+// MASTERBOOK_SKILL - An array with the skills you have learnt from Master Book.
+// - It's more flexible this way.
+// TEMPORARY:
+// @mb_BossId - Contains the MobID of the boss your party killed.
+// @mb_SkillId - Contains the SkillID which can be learnt with the boss.
+// @mb_ItemId - Contains the Feather Id to write (or whatever)
+// @mb_ItemAm - How many ink is required to write the skill
+// Remember: @mb_BossId will be reset to zero after 15 seconds from boss death.
+// Or upon logout. Or when changing maps. Temporary variables aren't reliable.
+//
+// @mb_BossId controls if you'll try to LEARN a skill, or READ the book.
+// Remember: A dialog prevents timer events from happening, but doesn't stops the timer.
+// TODO: Currently no way to get skill name from database (add getskillinfo() to server-plugin please)
+// TODO: Reset @mb_* when register_skill() finish
+// TODO: You cannot get Magic Feather anywhere in the game (yet)
+// TODO: See if the time (15s) is enough.
+// TODO: Skill level up
+// TODO: Use the data supplied by magic.txt
+
+- script #MasterBook NPC_HIDDEN,{
+
+
+ function register_skill {
+
+ setnpcdialogtitle l(.book_name$);
+
+ // If boss is set, but is negative, this means somebody else defeated it
+ if (@mb_BossId < 0)
+ {
+ mesc l("You did not defeat the boss, you can't learn any skills.");
+ @mb_BossId=0;
+ close;
+ }
+
+ // Report the boss you killed, and the boss level
+ .@mb_lvl=strmobinfo(3, @mb_BossId);
+ mesc l("You just defeated the following boss: @@ (Lv. @@)", strmobinfo(1, @mb_BossId), .@mb_lvl);
+
+ // The boss must have a skill
+ if (!@mb_SkillId)
+ {
+ mesc l("But there is no skill to be learnt from this boss.");
+ @mb_BossId=0;
+ close;
+ }
+ // You must have free pages
+ if (array_entries(MASTERBOOK_SKILL) >= MASTERBOOK_PAGES)
+ {
+ mesc l("But you ran out of empty pages on this book.");
+ @mb_BossId=0;
+ close;
+ }
+ // TODO: Party Level Range
+ // You must be at most 30 levels below the monster level
+ if (BaseLevel+30 < .@mb_lvl)
+ {
+ mesc l("But you are out of the boss level range.");
+ @mb_BossId=0;
+ close;
+ }
+ // You must have enough materials
+ if (countitem(@mb_ItemId) < @mb_ItemAm)
+ {
+ mesc l("But you do not have enough Magic Ink. (You need: @@ @@)", @mb_ItemAm, getitemlink(@mb_ItemId));
+ //@mb_BossId=0;
+ close;
+ }
+
+ // Allow you to check which skills are here to learn
+ mes "";
+ mesc l("You have: @@/@@ @@", countitem(@mb_ItemId), @mb_ItemAm, getitemlink(@mb_ItemId));
+ mesc l("Skill Available: %s", getskillname(@mb_SkillId));
+ select
+ rif(!getskilllv(@mb_SkillId), l("Learn Skill")),
+ l("Do not learn");
+ mes "";
+ if (@menu == 1)
+ {
+ delitem @mb_ItemId, @mb_ItemAm;
+ skill(@mb_SkillId, 1, 0);
+ array_push(MASTERBOOK_SKILL, @mb_SkillId);
+ closeclientdialog;
+ dispbottom l("You have learnt the skill.");
+ }
+ @mb_BossId=0;
+ close;
+ }
+
+
+ function read_book {
+
+ setnpcdialogtitle l(.book_name$);
+ mesc l("@@/@@ pages used.", array_entries(MASTERBOOK_SKILL), MASTERBOOK_PAGES);
+
+ mesc l("List of known master skills:");
+ mes "";
+ for (.@i = 0; .@i < getarraysize(MASTERBOOK_SKILL); ++.@i) {
+ mesc l("* Skill ID: @@", MASTERBOOK_SKILL[.@i]);
+ }
+ close;
+ }
+
+OnUse:
+ // We assume if @mb_BossId is set, everything else is set, too
+ if (@mb_BossId)
+ register_skill;
+ if (openbook())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = getitemname(MasterBook);
+ .distance = 1;
+ end;
+
+OnUnset:
+ @mb_BossId=0;
+ @mb_SkillId=0;
+ @mb_ItemId=0;
+ @mb_ItemAm=0;
+ end;
+}
+
+// Script Helper
+// BossSlain(npcname, "variable")
+function script BossSlain {
+ .@n$=getarg(0);
+ // Error
+ if (!playerattached())
+ return;
+ // Only the party which defeated the boss can learn the skill
+ getmapxy(.@m$, .@x, .@y, 0);
+ .@party=getcharid(1);
+ if (.@party > 0)
+ {
+ setd(getarg(1), .@party);
+ areatimer(.@m$, .@x-15, .@y-15, .@x+15, .@y+15, 10, .@n$+"::OnBossCheck");
+ mapannounce .@m$, "Boss deafeated by Party: " + getpartyname(.@party), bc_all;
+ }
+ else
+ {
+ setd(getarg(1), -2);
+ areatimer(.@m$, .@x-15, .@y-15, .@x+15, .@y+15, 10, .@n$+"::OnBossCheck");
+ addtimer(20, .@n$+"::OnBegin");
+ mapannounce .@m$, "Boss deafeated by: " + strcharinfo(0), bc_all;
+ }
+ return;
+}
+
+
diff --git a/npc/items/music_toys.txt b/npc/items/music_toys.txt
new file mode 100644
index 00000000..8583f65e
--- /dev/null
+++ b/npc/items/music_toys.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Authors:
+// Quillia
+// mekolat (legacy delay logic)
+// Description:
+// Allows the RubberBat to be squeezed.
+//
+
+- script RubberBat NPC_HIDDEN,{
+ close;
+
+OnUse:
+ if (gettimetick(2) - @lastbat < 2) close;
+ specialeffect(70, AREA, playerattached()); // effect 70 defined in client-data/effects.xml
+ @lastbat = gettimetick(2);
+
+ close;
+}
diff --git a/npc/items/rand_sc_heal.txt b/npc/items/rand_sc_heal.txt
new file mode 100644
index 00000000..e4b0875a
--- /dev/null
+++ b/npc/items/rand_sc_heal.txt
@@ -0,0 +1,85 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Random heal every x seconds.
+//
+// Variables:
+// @delay Second of healing
+// @min Min amount of healing
+// @max Max amount of healing
+// @type 1 Heal
+// 2 Other
+// 3 Special 1
+// 4 Special 2
+
+- script rand_sc_heal -1,{
+
+ // Add remaning bonus if the last one hasn't finished
+ function remaining_bonus
+ {
+ if (getstatus(getarg(0)))
+ {
+ .@old_val1 = getstatus(getarg(0), 1);
+ .@old_delay = getstatus(getarg(0), 4) * 1000;
+
+ // change the delay to prevent fast healing
+ if (.@old_delay > @delay)
+ {
+ @delay = .@old_delay;
+ @val1 += .@old_val1;
+ }
+ else
+ {
+ @val1 += (.@old_val1 * .@old_delay) / @delay;
+ }
+ }
+ else
+ {
+ @val1 = @val3;
+ }
+ return;
+ }
+
+OnUse:
+ if (@delay <= 0) close;
+
+ // minimum between @min and bVit / 2 * BaseLevel / 10
+ .@vitality_bonus = min(@min, readparam(bVit) * BaseLevel / 20);
+ .@rand_heal_val = rand(@min, @max);
+
+ // val1 is the heal value without the vitality bonus
+ @val1 = .@rand_heal_val / @delay;
+ @val3 = (.@rand_heal_val + .@vitality_bonus) / @delay;
+
+ if (@val1 <= 0) close;
+
+ @delay *= 1000; // Put the delay in ms
+
+ switch (@type)
+ {
+ case 1:
+ .@skill = SC_S_LIFEPOTION;
+ break;
+ case 2:
+ .@skill = SC_L_LIFEPOTION;
+ break;
+ case 3:
+ .@skill = SC_G_LIFEPOTION;
+ break;
+ case 4:
+ .@skill = SC_M_LIFEPOTION;
+ break;
+ default :
+ .@skill = 0;
+ break;
+ }
+ if (.@skill != 0)
+ {
+ remaining_bonus(.@skill);
+ sc_end .@skill;
+ sc_start2 .@skill, @delay, @val1, 1;
+ }
+
+ close;
+}
diff --git a/npc/items/recipes.txt b/npc/items/recipes.txt
new file mode 100644
index 00000000..42cdf51b
--- /dev/null
+++ b/npc/items/recipes.txt
@@ -0,0 +1,352 @@
+// Evol script.
+// Author:
+// Jesusalva
+// Micksha
+// Description:
+// Contains recipe books for Evol Online
+
+// showRecipe( recipe{, recipe...} )
+function script showRecipe {
+ freeloop(true);
+ for (.@a = 0; .@a < getargcount(); ++.@a) {
+ .@const$ = data_to_string(getarg(.@a));
+
+ if (startswith(.@const$, "Craft")) {
+ // infer the item constant from the craft constant
+ .@recipe = getarg(.@a);
+
+ .@item = string_to_data(substr(.@const$, 5, getstrlen(.@const$) - 1));
+ } else {
+ // infer the craft constant from the item constant
+ .@recipe = string_to_data(sprintf("Craft%s", .@const$));
+ .@item = getarg(.@a);
+ }
+
+ if (.@item <= 0) {
+ // target item not found
+ continue;
+ }
+
+ if (!RECIPES[.@recipe] && !debug) {
+ // does not have the recipe
+ continue;
+ }
+
+ for (.@inv = 0; .@inv < 9; ++.@inv) {
+ .@size = getcraftrecipe(.@recipe, .@inv, .@qty[0], .@item_id[0]);
+
+ if (.@size < 0) {
+ if (.@size == -1) {
+ // recipe does not exist
+ break;
+ }
+ // inventory does not exist
+ break;
+ }
+
+ mes(l(".:: %s Recipe ::.", getitemlink(.@item)));
+
+ for (.@it = 0; .@it < .@size; ++.@it) {
+ .@recipe_item = .@item_id[.@it];
+ .@recipe_qty = .@qty[.@it];
+
+ if (.@recipe_item <= 0) {
+ break;
+ }
+
+ mesc(sprintf("%d/%d %s", countitem(.@recipe_item), .@recipe_qty, getitemlink(.@recipe_item)));
+ }
+
+ mes("");
+ .@count++;
+ }
+ }
+ freeloop(false);
+
+ return .@count > 0;
+}
+
+- script #RecipeBook NPC_HIDDEN,{
+ function read_book;
+ function read_cooking;
+ function read_smithery;
+ function read_tailoring;
+ end;
+
+function read_book {
+ setnpcdialogtitle l(.book_name$);
+ mesc l("This book has several bookmarks. Which one will you open?");
+ next;
+ menuint
+ l("Cooking"), CRAFT_COOKING,
+ l("Alchemy"), CRAFT_ALCHEMY,
+ l("Smithery"), CRAFT_SMITHERY,
+ l("Tailoring"), CRAFT_TAILORING,
+ l("Jewelery"), CRAFT_JEWELERY;
+ mes "";
+ switch (@menuret) {
+ case CRAFT_COOKING:
+ read_cooking(); break;
+ case CRAFT_SMITHERY:
+ read_smithery(); break;
+ case CRAFT_TAILORING:
+ read_tailoring(); break;
+ default:
+ mesc l("Unfortunately, there is nothing on this bookmark.");
+ mesc l("Perhaps, in future, someone adds it to this world.");
+ break;
+ }
+ close2();
+ return;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+function read_cooking {
+
+ setnpcdialogtitle l("Cooking Recipes");
+
+ mesc l("Eating is a necessity, but cooking is an art.");
+ mesc l("(All items must be placed exactly in this order for cooking work.)");
+ next;
+ mesc l("List of known cooking recipes:");
+ mes "";
+ mes ".:: " + l("Sandwiches") + " ::.";
+ mes "";
+
+ showRecipe(CarpSandwich,
+ PioulegSandwich,
+ MananaSandwich);
+
+ mes "";
+ mes ".:: " + l("Stew") + " ::.";
+ mes "";
+
+ showRecipe(SailorStew,
+ SquirrelStew,
+ MoubooStew);
+
+ mes "";
+ mes ".:: " + l("Plates") + " ::.";
+ mes "";
+
+ showRecipe(SeafoodPlate,
+ BarbecuePlate,
+ VeggiePlate);
+
+ mes "";
+ mes ".:: " + l("Desserts") + " ::.";
+ mes "";
+
+ showRecipe(Donut,
+ BlueberryCake,
+ CarrotCake);
+ return;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+function read_smithery {
+
+ setnpcdialogtitle l("Smithery Recipes");
+
+ mesc l("You will trust your life to this, so you better do a good job!");
+ mesc l("(All items must be placed exactly in this order.)");
+ next;
+ mesc l("List of known smithery recipes:");
+
+ mes();
+ mesf(".:: %s ::.", l("Chest Armor"));
+ mes();
+
+ showRecipe(LegionTrainingShirt,
+ LegionCopperArmor,
+ Chainmail,
+ Snakeplate,
+ LightPlatemail,
+ JustifierChest,
+ LegionIronArmor,
+ WarlordPlate,
+ TerraniteArmor,
+ AssassinChest,
+ BlackArmor,
+ GoldenWarlordPlate);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Leg Armor"));
+ mes();
+
+ showRecipe(ChainmailSkirt,
+ TerranitePants,
+ AssassinPants);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Gloves"));
+ mes();
+
+ showRecipe(CopperArmbands,
+ BromenalGloves,
+ IronArmbands);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Boots"));
+ mes();
+
+ showRecipe(BromenalBoots,
+ WarlordBoots);
+
+ return;
+}
+
+function read_tailoring {
+ setnpcdialogtitle(l("Tailoring Recipes"));
+
+ mesc(l("(All items must be placed exactly in this order.)"));
+ next();
+ mesc(l("List of known tailoring recipes:"));
+
+ mes();
+ mesf(".:: %s ::.", l("Chest Armor"));
+ mes();
+
+ showRecipe(CreasedShirt,
+ ArtisTankTop,
+ VneckJumper,
+ SailorShirt,
+ FineDress,
+ SilkRobe,
+ ForestArmor,
+ ApprenticeRobe,
+ PeltJacket,
+ SorcererRobe,
+ WizardRobe,
+ EvocatorRobe);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Leg Armor"));
+ mes();
+
+ showRecipe(CreasedShorts,
+ CottonSkirt,
+ PirateShorts,
+ SilkPants,
+ BrownTrousers,
+ BanditTrousers,
+ JeansChaps,
+ LeatherTrousers);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Gloves"));
+ mes();
+
+ showRecipe(ShortGloves,
+ Armbands,
+ CottonGloves,
+ BanditGloves,
+ SilkGloves,
+ LeatherGloves,
+ AssassinGloves);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Boots"));
+ mes();
+
+ showRecipe(LousyMoccasins,
+ Slippers,
+ CottonBoots,
+ BanditBoots,
+ ManaSlippers,
+ SquirrelBoots,
+ LeatherBoots,
+ RidingBoots,
+ AssassinBoots);
+
+ return;
+}
+
+
+OnUse:
+ if (openbook())
+ read_book();
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = getitemname(RecipeBook);
+ .distance = 1;
+ end;
+}
+
+//////////////////////////////////////////////////////
+// Below this line are utils for Gacha. We use callfunc() on itemDB.
+// Types: see constants.db - everything is a bitwise here
+// Rarity: 1 - basic, 2 - intermediary, 4 - advanced, 8 - expert, 16 - master
+// Rarity: 1 - training, 2 - basic, 4 - advanced, 8 - expert, 16 - legendary
+// Keep in mind! Expert and Master blueprints must be restricted!
+// MakeBlueprint(type, rarity)
+function script MakeBlueprint {
+ .@type=getarg(0, -1);
+ .@rarity=getarg(1, 1);
+
+ if (.@type & CRAFT_COOKING) {
+
+ // ----------------------------------
+ if (.@rarity & CRAFT_BASIC) {
+ }
+ if (.@rarity & CRAFT_INTERMEDIARY) {
+ }
+ if (.@rarity & CRAFT_ADVANCED) {
+ }
+ if (.@rarity & CRAFT_EXPERT) {
+ }
+ if (.@rarity & CRAFT_MASTER) {
+ }
+ // ----------------------------------
+
+ }
+ else if (.@type & CRAFT_SMITHERY)
+ {
+
+ // ----------------------------------
+ if (.@rarity & CRAFT_BASIC) {
+ }
+ if (.@rarity & CRAFT_INTERMEDIARY) {
+ array_push(.@recipes, CraftInfantryHelmet);
+ }
+ if (.@rarity & CRAFT_ADVANCED) {
+ }
+ if (.@rarity & CRAFT_EXPERT) {
+ }
+ if (.@rarity & CRAFT_MASTER) {
+ }
+ // ----------------------------------
+
+ }
+
+ // We don't have a .@recipes array D:
+ if (array_entries(.@recipes) <= 0) {
+ dispbottom l("This blueprint was blank.");
+ return;
+ }
+
+ // Select a recipe randomly
+ .@rcp=any_of(.@recipes);
+
+ // Double precision failsafe
+ if (RECIPES[.@rcp])
+ .@rcp=any_of(.@recipes);
+
+ // Learn the recipe or lose the item (and gain some EXP)
+ if (RECIPES_[.@rcp]) {
+ dispbottom l("It was a recipe you already knew...");
+ getexp (BaseLevel+JobLevel)*rand2(1,.@rarity), JobLevel+rand2(1,.@rarity);
+ } else {
+ dispbottom l("Learned a new recipe!");
+ RECIPES[.@rcp]=true;
+ }
+ return;
+}
diff --git a/npc/items/shovel.txt b/npc/items/shovel.txt
new file mode 100644
index 00000000..b4a5a968
--- /dev/null
+++ b/npc/items/shovel.txt
@@ -0,0 +1,361 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Jesusalva
+// Description:
+// NPC to use shovel (dig, bury etc)
+
+- script Shovel -1,{
+
+ function CheckDigLocation {
+ getmapxy(.@map$, .@x, .@y, 0);
+
+ if (.@map$ != "001-1") {
+ if (getunits(BL_NPC, .@units, 1, .@map$, .@x - 1, .@y, .@x + 1, .@y + 1))
+ {
+ dispbottom(l("You cannot bury under a NPC!"));
+ return false;
+ }
+ }
+
+ // TODO: we should have a way to check for GROUNDTOP collisions too
+
+ for (.@i = 0; .@i < getarraysize(.WorldDigRect_Map$); .@i++)
+ {
+ if (!strcmp(.WorldDigRect_Map$[.@i], .@map$) &&
+ .WorldDigRect_x1[.@i] <= .@x &&
+ .WorldDigRect_x2[.@i] >= .@x &&
+ .WorldDigRect_y1[.@i] <= .@y &&
+ .WorldDigRect_y2[.@i] >= .@y)
+ {
+ return true;
+ }
+ }
+
+ dispbottom(l("You can't use the shovel here."));
+ return false;
+ }
+
+ function AddDigRect {
+ if (getargcount() < 5)
+ {
+ consolemes(CONSOLEMES_ERROR, "usage: AddDigRect(map$,x1,y1,x2,y2)");
+ return 0;
+ }
+ .@map$ = str(getarg(0));
+ .@x1 = getarg(1);
+ .@y1 = getarg(2);
+ .@x2 = getarg(3);
+ .@y2 = getarg(4);
+ .@size = getarraysize(.WorldDigRect_Map$);
+ .WorldDigRect_Map$[.@size] = .@map$;
+ .WorldDigRect_x1[.@size] = .@x1;
+ .WorldDigRect_y1[.@size] = .@y1;
+ .WorldDigRect_x2[.@size] = .@x2;
+ .WorldDigRect_y2[.@size] = .@y2;
+ return 1;
+ }
+
+ function AddMapDigRect {
+ .@m$=getarg(0);
+ .@x=getmapinfo(MAPINFO_SIZE_X, .@m$)-20;
+ .@y=getmapinfo(MAPINFO_SIZE_Y, .@m$)-20;
+ return AddDigRect(.@m$, 20, 20, .@x, .@y);
+ }
+
+ function PlayerIsTired {
+ if (is_evtc())
+ return false; // event coordinators are never tired
+
+ .@tick = gettimetick(1);
+ .@playertick = .PlayerTiredTime - readparam(bStr);
+ if (@ShovelLastUsed + max(4, .@playertick) > .@tick)
+ {
+ narrator S_FIRST_BLANK_LINE,
+ l("You are exhausted, you should rest a bit.");
+ return true;
+ }
+ @ShovelLastUsed = .@tick;
+ return false;
+ }
+
+ function Dig {
+ getmapxy(.@map$, .@x, .@y, 0);
+ for (.@i = 0; .@i < getarraysize($WorldBuriedTreasures_id); .@i++)
+ {
+ if (!strcmp($WorldBuriedTreasures_map$[.@i], .@map$) &&
+ $WorldBuriedTreasures_x[.@i] == .@x &&
+ $WorldBuriedTreasures_y[.@i] == .@y)
+ {
+ .@id = $WorldBuriedTreasures_id[.@i];
+ .@amount = $WorldBuriedTreasures_amount[.@i];
+ deletearray $WorldBuriedTreasures_id[.@i], 1;
+ deletearray $WorldBuriedTreasures_amount[.@i], 1;
+ deletearray $WorldBuriedTreasures_map$[.@i], 1;
+ deletearray $WorldBuriedTreasures_x[.@i], 1;
+ deletearray $WorldBuriedTreasures_y[.@i], 1;
+ getitem .@id, .@amount;
+ narrator S_FIRST_BLANK_LINE,
+ l("You found something!"),
+ l("It's @@ @@.", .@amount, getitemname(.@id));
+ return 1;
+ }
+ }
+ narrator S_FIRST_BLANK_LINE, l("Sadly, you found nothing but dirt.");
+ return 0;
+ }
+
+ function Bury {
+ narrator S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE, l("What would you like to bury?");
+ .@items$ = "";
+
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+
+ .@id = requestitem();
+
+ // If ID is invalid, there's not enough items, it is an Iron Shovel, it is bound = Cannot bury
+ // NOBODY bypass notrade check. (ITR_NONE is 0)
+ if (.@id < 1) close;
+ if (.@id < 1 || countitem(.@id) < 1 || .@id == IronShovel || checkbound(.@id) ||
+ (!getiteminfo(.@id, ITEMINFO_TRADE))
+ ) {
+ @ShovelLastUsed = 0;
+ if (.@id == IronShovel || .@id == SteelShovel || checkbound(.@id))
+ mesc l("You cannot bury this item!");
+ else if (!getiteminfo(.@id, ITEMINFO_TRADE))
+ mesc l("This item is too precious, you cannot part with it!");
+ else
+ mesc l("You give up.");
+ close;
+ return;
+ }
+
+ .@amount = 1;
+ if (countitem(.@id) > 1)
+ {
+ narrator S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE, l("Amount?");
+ input .@amount, 1, countitem(.@id);
+ }
+
+ getmapxy(.@map$, .@x, .@y, 0);
+
+ delitem .@id, .@amount;
+ .@wtc = getarraysize($WorldBuriedTreasures_id);
+ $WorldBuriedTreasures_id[.@wtc] = .@id;
+ $WorldBuriedTreasures_amount[.@wtc] = .@amount;
+ $WorldBuriedTreasures_map$[.@wtc] = .@map$;
+ $WorldBuriedTreasures_x[.@wtc] = .@x;
+ $WorldBuriedTreasures_y[.@wtc] = .@y;
+ narrator S_FIRST_BLANK_LINE, l("You buried @@ @@.", .@amount, getitemname(.@id));
+
+ return true;
+ }
+
+ function ShovelQuests {
+ getmapxy(.@map$, .@x, .@y, 0);
+ for (.@i = 0; .@i < getarraysize(ShovelQuests_func$); .@i++)
+ {
+ if (!strcmp(ShovelQuests_map$[.@i], .@map$) &&
+ ShovelQuests_x[.@i] == .@x &&
+ ShovelQuests_y[.@i] == .@y)
+ {
+ .@func$ = ShovelQuests_func$[.@i];
+ deletearray ShovelQuests_func$[.@i], 1;
+ deletearray ShovelQuests_map$[.@i], 1;
+ deletearray ShovelQuests_x[.@i], 1;
+ deletearray ShovelQuests_y[.@i], 1;
+ callfunc(.@func$);
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+OnUse:
+ if (!CheckDigLocation())
+ end;
+
+ narrator S_LAST_BLANK_LINE,
+ l("You hold the shovel in your hands."),
+ l("What are you going to do?");
+
+ .@action = select(
+ l("Dig."),
+ l("Bury."),
+ l("Nothing."));
+
+ switch(.@action)
+ {
+ case 1:
+ if (PlayerIsTired())
+ close;
+ if (!ShovelQuests())
+ Dig();
+ break;
+ case 2:
+ if (PlayerIsTired())
+ close;
+ Bury();
+ break;
+ case 3:
+ narrator S_FIRST_BLANK_LINE, l("You hide your shovel.");
+ break;
+ }
+ close;
+
+OnHour00:
+ if (playerattached())
+ @ShovelLastUsed = 0;
+ end;
+
+OnInit:
+ .PlayerTiredTime = 20;
+
+ // Partial maps
+ AddDigRect("001-1", 172, 26, 200, 48);
+ AddDigRect("001-1", 198, 60, 201, 63);
+ AddDigRect("008-1-1", 32, 42, 46, 88);
+ AddDigRect("008-1-2", 40, 52, 114, 146);
+ AddDigRect("012-1", 44, 21, 139, 47);
+
+ // Whole maps
+ AddMapDigRect("008-1");
+ AddMapDigRect("008-3-5");
+ AddMapDigRect("012-3-1");
+ end;
+
+}
+
+function script shovel_addquest {
+ if (getargcount() < 4)
+ {
+ consolemes(CONSOLEMES_ERROR, "usage: shovel_addquest(map$,x,y,func$)");
+ return 0;
+ }
+ .@map$ = str(getarg(0));
+ .@x = getarg(1);
+ .@y = getarg(2);
+ .@func$ = str(getarg(3));
+ .@size = getarraysize(ShovelQuests_func$);
+ ShovelQuests_func$[.@size] = .@func$;
+ ShovelQuests_map$[.@size] = .@map$;
+ ShovelQuests_x[.@size] = .@x;
+ ShovelQuests_y[.@size] = .@y;
+ return 1;
+}
+
+function script shovel_adddigrect {
+ if (getargcount() < 5)
+ {
+ consolemes(CONSOLEMES_ERROR, "usage: shovel_adddigrect(map$,x1,y1,x2,y2)");
+ return 0;
+ }
+ .@map$ = str(getarg(0));
+ .@x1 = getarg(1);
+ .@y1 = getarg(2);
+ .@x2 = getarg(3);
+ .@y2 = getarg(4);
+ .@size = getarraysize(getvariableofnpc(.WorldDigRect_Map$, strnpcinfo(3)));
+ set getvariableofnpc(.WorldDigRect_Map$[.@size], strnpcinfo(3)), .@map$;
+ set getvariableofnpc(.WorldDigRect_x1[.@size], strnpcinfo(3)), .@x1;
+ set getvariableofnpc(.WorldDigRect_y1[.@size], strnpcinfo(3)), .@y1;
+ set getvariableofnpc(.WorldDigRect_x2[.@size], strnpcinfo(3)), .@x2;
+ set getvariableofnpc(.WorldDigRect_y2[.@size], strnpcinfo(3)), .@y2;
+ return 1;
+}
+
+// [Treasure Map] functions
+
+function script shovel_getcity {
+ .@a$=getarg(0);
+
+ // else is not required (return prevails)
+ if (.@a$ == "001-1")
+ return l("Artis East Beach");
+ if (.@a$ == "008-1")
+ return l("East Woodlands");
+ if (.@a$ == "008-1-1")
+ return l("West Woodland Beach");
+ if (.@a$ == "008-1-2")
+ return l("Swamps");
+ if (.@a$ == "008-3-5")
+ return l("Hurnscald Bandit Cave");
+ if (.@a$ == "012-1")
+ return l("Candor North");
+ if (.@a$ == "012-3-1")
+ return l("Candor Main Cave");
+
+ return .@a$;
+}
+
+function script shovel_randomtreasure {
+ .@id=any(TreasureKey,CoinBag,CoinBag,CoinBag,Coal,
+ Diamond,Ruby,Emerald,Sapphire,Topaz,Amethyst,
+ CrudeDiamond,CrudeRuby,CrudeEmerald,
+ CrudeSapphire,CrudeTopaz,CrudeAmethyst,
+ MaggotSlimePotion, LargeMana, LargeHealing);
+ delitem TreasureMap, 1;
+ .@amount=any(1,1,2);
+ // Very Commons
+ if (.@id == CoinBag || .@id == MaggotSlimePotion || .@id == TreasureKey)
+ .@amount+=any(0,1,0,1,2);
+ // Super commons
+ if (.@id == LargeMana || .@id == LargeHealing)
+ .@amount+=rand2(0,8);
+ // Rares
+ if (.@id == Coal)
+ .@amount=1;
+ getitem .@id, .@amount;
+ ShovelQuests_AssignedMAP$="";
+ ShovelQuests_AssignedX=0;
+ ShovelQuests_AssignedY=0;
+
+ mesn strcharinfo(0);
+ mesc l("You found something!");
+ mesc l("It's %d %s.", .@amount, getitemlink(.@id));
+ next;
+ closeclientdialog;
+ return;
+}
+
+function script shovel_genrandtreasure {
+ .@m$=any("008-1", "008-1-1", "008-1-2", "008-3-5",
+ "012-1", "012-3-1");
+
+ // Prepare good defaults
+ .@x1=.@y1=20;
+ .@x2=getmapinfo(MAPINFO_SIZE_X, .@m$)-20;
+ .@y2=getmapinfo(MAPINFO_SIZE_Y, .@m$)-20;
+
+ // Default overrides
+ if (.@m$ == "008-1-1") {
+ // West Woodland Beach
+ .@x1=32; .@y1=42;
+ .@x2=46; .@y2=88;
+ } else if (.@m$ == "008-1-2") {
+ // Swamps
+ .@x1=40; .@y1=52;
+ .@x2=114; .@y2=146;
+ } else if (.@m$ == "012-1") {
+ // Candor North
+ .@x1=44; .@y1=139;
+ .@x2=21; .@y2=47;
+ }
+
+ // Dangerous, but I never had issues with this
+ do {
+ .@x=rand2(.@x1, .@x2);
+ .@y=rand2(.@y1, .@y2);
+ } while (!checkcell(.@m$, .@x, .@y, cell_chkpass));
+
+ // Success
+ if (checkcell(.@m$, .@x, .@y, cell_chkpass)) {
+ shovel_addquest(.@m$, .@x, .@y, "shovel_randomtreasure");
+ ShovelQuests_AssignedMAP$=shovel_getcity(.@m$);
+ ShovelQuests_AssignedX=.@x;
+ ShovelQuests_AssignedY=.@y;
+ }
+ return;
+}
+
+
diff --git a/npc/marine-2/_import.txt b/npc/marine-2/_import.txt
new file mode 100644
index 00000000..006ce407
--- /dev/null
+++ b/npc/marine-2/_import.txt
@@ -0,0 +1,4 @@
+// Map marine-2: Ocean
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/marine-2/_mobs.txt",
+"npc/marine-2/main.txt",
diff --git a/npc/marine-2/_mobs.txt b/npc/marine-2/_mobs.txt
new file mode 100644
index 00000000..a41d1a2c
--- /dev/null
+++ b/npc/marine-2/_mobs.txt
@@ -0,0 +1,4 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map marine-2: Ocean mobs
+marine-2,32,32,9,3 monster Croc 1006,2,13000,12000
+marine-2,31,33,9,3 monster Tipiou 1016,1,14000,14000
diff --git a/npc/marine-2/main.txt b/npc/marine-2/main.txt
new file mode 100644
index 00000000..9ab0dfc0
--- /dev/null
+++ b/npc/marine-2/main.txt
@@ -0,0 +1,60 @@
+// Moubootaur Legends script
+// Originals from TMW-BR
+// Imported by Jesusalva
+
+marine-2,0,0,0 script #MarineShip NPC_HIDDEN,{
+ end;
+
+OnEvent:
+ // Handle travel
+ if (@timer_navio_running == 0) end;
+ if (PC_DEST$ == "Tulim") goto L_Tulim;
+ else if (PC_DEST$ == "Hurns") goto L_Hurns;
+ else if (PC_DEST$ == "Candor") goto L_Candor;
+ else if (PC_DEST$ == "Artis") goto L_Artis;
+ else if (PC_DEST$ == "Argaes") goto L_Argaes;
+ else goto L_Error;
+ end;
+
+L_Tulim:
+ EnterTown("Tulim", true);
+ dispbottom l("%s disembarks at Tulimshar.", strcharinfo(0));
+ end;
+
+L_Hurns:
+ EnterTown("Hurns", true);
+ dispbottom l("%s disembarks at Hurnscald.", strcharinfo(0));
+ end;
+
+L_Candor:
+ EnterTown("Candor", true);
+ dispbottom l("%s disembarks at Candor.", strcharinfo(0));
+ end;
+
+L_Artis:
+ EnterTown("Artis", true);
+ dispbottom l("%s disembarks at Artis.", strcharinfo(0));
+ end;
+
+L_Argaes:
+ if (getq(General_Narrator) == 1) {
+ warp "000-0-1", 26, 28;
+ } else {
+ EnterTown("Argaes", true);
+ dispbottom l("%s disembarks at Argaes.", strcharinfo(0));
+ }
+ end;
+
+L_Error:
+ consolemes(CONSOLEMES_ERROR, "PLAYER INVALID PC_DEST ON #MarineShip: " + PC_DEST$);
+ ReturnLastTown();
+ dispbottom l("An error on your travel happened. Please report.");
+ end;
+}
+
+function script TravelFix {
+ if (getmap() == "marine-2")
+ ReturnLastTown();
+ return;
+}
+
diff --git a/npc/marine/_import.txt b/npc/marine/_import.txt
new file mode 100644
index 00000000..6ab1ff31
--- /dev/null
+++ b/npc/marine/_import.txt
@@ -0,0 +1,4 @@
+// Map marine: La Marine
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/marine/_mobs.txt",
+"npc/marine/saluc.txt",
diff --git a/npc/marine/_mobs.txt b/npc/marine/_mobs.txt
new file mode 100644
index 00000000..57623607
--- /dev/null
+++ b/npc/marine/_mobs.txt
@@ -0,0 +1,3 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map marine: La Marine mobs
+marine,31,26,9,4 monster Piou 1002,2,30000,20000
diff --git a/npc/marine/saluc.txt b/npc/marine/saluc.txt
new file mode 100644
index 00000000..dc3b9897
--- /dev/null
+++ b/npc/marine/saluc.txt
@@ -0,0 +1,137 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Saluc Golden Beard, one of the greediest ship captains in Argaes.
+// THIS IS A PLACEHOLDER!
+
+// If you logout on instance, ensure TravelFix() can fix your position
+marine mapflag nosave marine-2,40,32
+
+// Ship captain
+marine,25,24,0 script Saluc Golden Beard NPC_HAL,{
+ function confirmTravel;
+ function artisTravel;
+ if (.artis)
+ artisTravel();
+ mesn;
+ mesq l("Hello, adventurer! I am Saluc the Golden Beard!");
+ next;
+ mesn;
+ mesq l("No, I'm not a scammer! You'll get a ship travel with me, I just... charge a bit more for profit.");
+ next;
+ mesn;
+ mesq l("So, to where you want to go?");
+ mesc l("You are currently at %s.", LOCATION$);
+ menuint
+ rif(LOCATION$ != "Tulim", l("To Tulimshar")), TP_TULIM,
+ rif(LOCATION$ != "Hurns", l("To Hurnscald")), TP_HURNS,
+ rif(LOCATION$ != "Candor", l("To Candor")), TP_CANDOR,
+ l("No, I'll save my money."), TP_NONE;
+ mes "";
+ if (@menuret == TP_NONE)
+ close;
+ mesn;
+ mesq l("Excellent! Hehehe... That'll be %d E!", .price);
+ if (.artis)
+ mesc l("This travel option is NOT advised for new players."), 1;
+ if (Zeny < .price)
+ close;
+ next;
+ mesc l("Travel?");
+ if (askyesno() == ASK_NO || Zeny < .price)
+ close;
+
+ mesn;
+ mesq l("Hehehe... All aboard!");
+ next;
+ confirmTravel(.price);
+ close;
+
+/* Special Artis dialog */
+function artisTravel {
+ mesn;
+ mesq l("Hello, adventurer! I am William D. and I am the captain of this frigate!");
+ next;
+ mesn;
+ mesq l("Gema IV is a good trading ship, but the Legion has requisitioned it...");
+ next;
+ .@price=.price;
+ // NOT a typo; You can self-smuggle yourself w/o the commendation leter.
+ // ...For now.
+ if (getq(Artis_Legion_Progress) >= 6) {
+ mesn;
+ mesq l("Did Q'Anon sent you? Are you enrolled in the Argaes expedition? We're leaving soon so hurry up!");
+ .@price=0;
+ } else {
+ mesn;
+ mesq l("I'm providing transport to the Argaes expedition.");
+ mesc l("William looks around to make sure no one else is listening and continues.");
+ next;
+ mesn;
+ mesq l("Heh, are you curious with the new world? I can make room for an extra \"Crew\" member, if ya catch my drift...");
+ mesc l("NEW PLAYERS: This route is for veterans only."), 1;
+ }
+ next;
+ mesn;
+ mesq l("So, will you board?");
+ next;
+ menuint
+ l("To Argaes!"), TP_ARGAES,
+ l("No, I'll save my money."), TP_NONE;
+ mes "";
+ if (@menuret == TP_NONE)
+ close;
+ if (Zeny < .@price)
+ close;
+ next;
+ mesc l("Travel?");
+ if (.@price)
+ mesc l("This option is not advised."), 1;
+ if (askyesno() == ASK_NO || Zeny < .@price)
+ close;
+
+ mesn;
+ mesq l("Hehehe... All aboard!");
+ next;
+ confirmTravel(.@price);
+ close;
+ return;
+}
+
+/* Warp players to their travel */
+function confirmTravel {
+ closeclientdialog;
+
+ Zeny-=getarg(0);
+ .@i=array_find($@LOCMASTER_TP, @menuret);
+ PC_DEST$=$@LOCMASTER_LOC$[.@i];
+ @timer_navio_running = 1;
+ addtimer (.artis ? 140000 : 50000), "#MarineShip::OnEvent"; // One minute
+ warp "marine-2", 40, 32;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ .price = 100; // Current a constant, but maybe... In future...
+ .artis = false;
+ end;
+
+OnInstanceInit:
+ // Smart Replacement for Artis' version
+ if (instance_mapname("marine") == "marine@Arti") {
+ setnpcdisplay(instance_npcname(.name$), "William D.");
+ .price = 10000;
+ .artis = true;
+ }
+ end;
+}
+
+// Exit door
+marine,42,25,0 script Exit#Marine NPC_HIDDEN,0,0,{
+OnTouch:
+ ReturnLastTown();
+ end;
+}
+
diff --git a/npc/pre-re/scripts_main.conf b/npc/pre-re/scripts_main.conf
new file mode 100644
index 00000000..8574cb92
--- /dev/null
+++ b/npc/pre-re/scripts_main.conf
@@ -0,0 +1,4 @@
+// Only files that are included here will be read by the server
+npc_global_list: (
+@include "npc/scripts.conf"
+) // npc_global_list
diff --git a/npc/scripts.conf b/npc/scripts.conf
new file mode 100644
index 00000000..210a1d78
--- /dev/null
+++ b/npc/scripts.conf
@@ -0,0 +1,178 @@
+// This is the main script import file
+
+// Critical functions
+"npc/functions/permissions.txt",
+
+// General-purpose Framework functions
+"npc/functions/array.txt",
+"npc/functions/time.txt",
+"npc/functions/timer.txt",
+"npc/functions/input.txt",
+"npc/functions/string.txt",
+"npc/functions/RNGesus.txt",
+"npc/functions/math.txt",
+"npc/functions/warp.txt",
+"npc/functions/bodytype.txt",
+"npc/functions/bitwise.txt",
+"npc/functions/event-listeners.txt",
+
+// Misc functions
+"npc/functions/main.txt",
+"npc/functions/legacy.txt",
+"npc/functions/vault.txt",
+"npc/functions/player-cache.txt",
+"npc/functions/asleep.txt",
+"npc/functions/clientversion.txt",
+"npc/functions/doors.txt",
+"npc/functions/goodbye.txt",
+"npc/functions/barber.txt",
+"npc/functions/global_event_handler.txt",
+"npc/functions/hammocks.txt",
+"npc/functions/harbours.txt",
+"npc/functions/hello.txt",
+"npc/functions/inventoryplace.txt",
+"npc/functions/legiontalk.txt",
+"npc/functions/npcmove.txt",
+"npc/functions/masks.txt",
+"npc/functions/spotlight.txt",
+"npc/functions/openbook.txt",
+"npc/functions/questgen.txt",
+"npc/functions/sailordialogue.txt",
+"npc/functions/sailortalk.txt",
+"npc/functions/savepoint.txt",
+"npc/functions/beds.txt",
+"npc/functions/shops.txt",
+"npc/functions/villagertalk.txt",
+"npc/functions/npcmovegraph.txt",
+"npc/functions/fishing.txt",
+"npc/functions/mouboofunc.txt",
+"npc/functions/generic-text.txt",
+"npc/functions/asklanguage.txt",
+"npc/functions/game-rules.txt",
+"npc/functions/refine.txt",
+"npc/functions/riddle.txt",
+"npc/functions/bank.txt",
+"npc/functions/confused-tree-dict.txt",
+"npc/functions/treasure.txt",
+"npc/functions/afk.txt",
+"npc/functions/resetstatus.txt",
+
+// May rely on custom functions and thus must be handled by last
+"npc/functions/util.txt",
+"npc/functions/faction.txt",
+"npc/functions/scoreboards.txt",
+"npc/functions/manhole.txt",
+"npc/functions/skills.txt",
+"npc/functions/lockpicks.txt",
+"npc/functions/crafting.txt",
+"npc/functions/referral.txt",
+"npc/functions/music.txt",
+"npc/functions/casino.txt",
+"npc/functions/daily.txt",
+"npc/functions/libquest.txt",
+"npc/functions/soul-menhir.txt",
+
+// Quest debug
+"npc/functions/quest-debug/functions.txt",
+
+// Drasil Island
+"npc/functions/quest-debug/000-ShipQuests_Julia.txt",
+"npc/functions/quest-debug/001-ShipQuests_Arpan.txt",
+"npc/functions/quest-debug/002-ShipQuests_Alige.txt",
+"npc/functions/quest-debug/003-ShipQuests_Peter.txt",
+"npc/functions/quest-debug/004-ShipQuests_Nard.txt",
+"npc/functions/quest-debug/005-ShipQuests_Knife.txt",
+"npc/functions/quest-debug/006-ShipQuests_ArpanMoney.txt",
+"npc/functions/quest-debug/007-ShipQuests_Door.txt",
+"npc/functions/quest-debug/008-ShipQuests_Couwan.txt",
+"npc/functions/quest-debug/009-ShipQuests_TreasureChest.txt",
+"npc/functions/quest-debug/010-ShipQuests_Ale.txt",
+"npc/functions/quest-debug/011-ShipQuests_Astapolos.txt",
+"npc/functions/quest-debug/012-ShipQuests_Gulukan.txt",
+"npc/functions/quest-debug/013-ShipQuests_Jalad.txt",
+"npc/functions/quest-debug/014-ShipQuests_QMuller.txt",
+"npc/functions/quest-debug/015-ShipQuests_Tibbo.txt",
+"npc/functions/quest-debug/016-ShipQuests_Gugli.txt",
+"npc/functions/quest-debug/017-ShipQuests_ChefGado.txt",
+"npc/functions/quest-debug/018-General_Cookies.txt",
+
+// Artis Town
+"npc/functions/quest-debug/020-ArtisQuests_LazyBrother.txt",
+"npc/functions/quest-debug/021-ArtisQuests_Urchin.txt",
+"npc/functions/quest-debug/022-ArtisQuests_CatchPiou.txt",
+"npc/functions/quest-debug/023-ArtisQuests_Fishman.txt",
+"npc/functions/quest-debug/024-ArtisQuests_QOnan.txt",
+// 025: ID AVAILABLE
+"npc/functions/quest-debug/026-General_Rumly.txt",
+"npc/functions/quest-debug/027-ArtisQuests_Enora.txt",
+// 028: ID AVAILABLE
+"npc/functions/quest-debug/029-ArtisQuests_Fexil.txt",
+"npc/functions/quest-debug/030-ArtisQuests_Lloyd.txt",
+"npc/functions/quest-debug/031-General_Janus.txt",
+"npc/functions/quest-debug/032-ArtisQuests_MonaDad.txt",
+"npc/functions/quest-debug/033-Artis_Legion_Progress.txt",
+"npc/functions/quest-debug/034-ArtisQuests_TrainingLegion.txt",
+"npc/functions/quest-debug/035-ThiefQuests_Artis.txt",
+
+// Argaes Quests
+"npc/functions/quest-debug/050-HurnscaldQuests_Hinnak.txt",
+"npc/functions/quest-debug/051-HurnscaldQuests_Soup.txt",
+"npc/functions/quest-debug/052-HurnscaldQuests_Inspector.txt",
+"npc/functions/quest-debug/053-HurnscaldQuests_ForestBow.txt",
+"npc/functions/quest-debug/054-HurnscaldQuests_WoodenShield.txt",
+"npc/functions/quest-debug/055-General_Cooking.txt",
+"npc/functions/quest-debug/056-General_Brotherhood.txt",
+"npc/functions/quest-debug/057-HurnscaldQuests_Kfahr.txt",
+"npc/functions/quest-debug/058-ArgaesQuest_Galimatia.txt",
+"npc/functions/quest-debug/059-HurnscaldQuests_Rossy.txt",
+// 60 busy for blood donation quest
+"npc/functions/quest-debug/061-General_Hal.txt",
+
+// Event and General Quests
+"npc/functions/quest-debug/100-General_Narrator.txt",
+// 101: removed quest (Halloween_VisitArtis)
+// 102: removed quest (Halloween_BarrelQuest)
+
+// Item functions
+"npc/items/cookie.txt",
+"npc/items/croconut.txt",
+"npc/items/shovel.txt",
+"npc/items/rand_sc_heal.txt",
+"npc/items/recipes.txt",
+"npc/items/master_skillbook.txt",
+"npc/items/music_toys.txt",
+"npc/items/gift.txt",
+
+// custom atcommands
+"npc/commands/gm.txt",
+"npc/commands/music.txt",
+"npc/commands/warp.txt",
+"npc/commands/zeny.txt",
+"npc/commands/motd-debug-text.txt",
+"npc/commands/motd.txt",
+"npc/commands/mobinfo.txt",
+"npc/commands/scheduled-broadcasts.txt",
+"npc/commands/rate-management.txt",
+"npc/commands/event.txt",
+"npc/commands/debug-look.txt",
+"npc/commands/debug-quest.txt",
+"npc/commands/debug-skill.txt",
+"npc/commands/debug-preset.txt",
+"npc/commands/debug.txt",
+"npc/commands/super-menu.txt",
+"npc/commands/resync.txt",
+"npc/commands/python.txt",
+"npc/commands/bodytype.txt",
+
+// config script
+"npc/config/hairstyle_config.txt",
+"npc/config/location.txt",
+"npc/config/magic.txt",
+
+// placeholder scripts
+//"npc/placeholder/angus.txt",
+//"npc/placeholder/caul.txt",
+//"npc/placeholder/receptionist.txt",
+
+// Maps specific scripts
+@include "npc/_import.txt"
diff --git a/npc/sec_pri/_import.txt b/npc/sec_pri/_import.txt
new file mode 100644
index 00000000..e6c274dd
--- /dev/null
+++ b/npc/sec_pri/_import.txt
@@ -0,0 +1,3 @@
+// Map sec_pri: Jail
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/sec_pri/redirect.txt",
diff --git a/npc/sec_pri/redirect.txt b/npc/sec_pri/redirect.txt
new file mode 100644
index 00000000..bd46b987
--- /dev/null
+++ b/npc/sec_pri/redirect.txt
@@ -0,0 +1,12 @@
+// The Mana World Script
+// Author:
+// Jesusalva
+// Controls additional jail cells
+
+sec_pri,49,75,0 script #JailIntWarp NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ slide any(29, 33), 75;
+ end;
+}
diff --git a/npc/test/_import.txt b/npc/test/_import.txt
new file mode 100644
index 00000000..69324674
--- /dev/null
+++ b/npc/test/_import.txt
@@ -0,0 +1,12 @@
+// Map test: test
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/test/_mobs.txt",
+"npc/test/mapflags.txt",
+"npc/test/npc1.txt",
+"npc/test/npc2.txt",
+"npc/test/npc3.txt",
+"npc/test/npc4.txt",
+"npc/test/npc5.txt",
+"npc/test/npc6.txt",
+"npc/test/test1.txt",
+"npc/test/test2.txt",
diff --git a/npc/test/_mobs.txt b/npc/test/_mobs.txt
new file mode 100644
index 00000000..8bab3101
--- /dev/null
+++ b/npc/test/_mobs.txt
@@ -0,0 +1,15 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map test: test mobs
+test,38,12,1,1 monster Piou 1002,1,1000,1000
+test,38,12,1,1 monster Tortuga 1004,1,1000,1000
+test,44,12,1,1 monster Piou 1002,3,1000,1000
+test,48,10,1,1 monster Tortuga 1004,3,1000,1000
+test,48,10,0,0 monster Piou 1002,1,1000,1000
+test,48,10,0,0 monster Ratto 1005,1,1000,1000
+test,54,10,1,1 monster Piou 1002,3,1000,1000
+test,68,9,0,0 monster Piou 1002,3,1000,1000
+test,68,9,0,0 monster Ratto 1005,1,1000,1000
+test,68,9,1,1 monster Tortuga 1004,3,1000,1000
+test,76,10,1,1 monster Piou 1002,3,1000,1000
+test,76,10,1,1 monster Ratto 1005,1,1000,1000
+test,78,4,1,1 monster Ratto 1005,3,1000,1000
diff --git a/npc/test/mapflags.txt b/npc/test/mapflags.txt
new file mode 100644
index 00000000..6f3199ae
--- /dev/null
+++ b/npc/test/mapflags.txt
@@ -0,0 +1,2 @@
+test mapflag mask 5
+test mapflag town
diff --git a/npc/test/npc1.txt b/npc/test/npc1.txt
new file mode 100644
index 00000000..31a6a689
--- /dev/null
+++ b/npc/test/npc1.txt
@@ -0,0 +1,712 @@
+// Evol scripts.
+// Author:
+// 4144
+// Description:
+// test npc1
+
+test,10,10,0 script npc1#door NPC_HIDDEN,0,1,{
+OnTouch:
+ warp "test", 20, 20;
+ close;
+OnUnTouch:
+ doevent "npc1::OnUnTouch";
+}
+
+test,10,10,0 script npc1 NPC_TEST1,3,3,{
+ function areatest
+ {
+ mesn;
+ mes "getareausers(\"test\", 7, 7, 13, 13): " + getareausers("test", 7, 7, 13, 13);
+ mes "getareausers(7, 7, 13, 13): " + getareausers(7, 7, 13, 13);
+ mes "getareausers(\"test\"): " + getareausers("test");
+ mes "getareausers(): " + getareausers();
+ mes "getareausers(\"test\", 1): " + getareausers("test", 1);
+ mes "getareausers(1): " + getareausers(1);
+ next;
+ return;
+ }
+
+L_Start:
+ switch (select(
+ "show area",
+ "map",
+ "pc",
+ "change npc direction",
+ "quest test",
+ "cart",
+ "items",
+ "chat",
+ "wall",
+ "craft",
+ "hashtable",
+ "instance",
+ "mercenary",
+ "npc",
+ "clan"))
+ {
+ case 1:
+ areatest;
+ break;
+ case 2:
+ while(1)
+ {
+ .@mask = getmapmask("test");
+ mes "current mask: " + str(.@mask);
+ switch (select("show sand:show grass:show fog:hide fog:back"))
+ {
+ case 1:
+ addremovemapmask "test", 4, 8;
+ break;
+ case 2:
+ addremovemapmask "test", 8, 4;
+ break;
+ case 3:
+ addmapmask "test", 2;
+ break;
+ case 4:
+ removemapmask "test", 2;
+ break;
+ case 5:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+
+ case 3:
+ while(1)
+ {
+ switch (select("change sex:setmount 0:setmount 1:setmount 2:test command:back"))
+ {
+ case 1:
+ changecharsex;
+ break;
+ case 2:
+ setmount 0;
+ break;
+ case 3:
+ setmount 1;
+ break;
+ case 4:
+ setmount 2;
+ break;
+ case 5:
+ clientcommand "emote 1";
+ break;
+ case 6:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 4:
+ for (.@f = 0; .@f < 9; .@f ++)
+ {
+ mes "" + .@f;
+ .dir = .@f;
+ next;
+ }
+ break;
+ case 5:
+ mes "current";
+ .@val1 = getq(ShipQuests_Gugli);
+ .@val2 = getq2(ShipQuests_Gugli);
+ .@val3 = getq3(ShipQuests_Gugli);
+ .@valTime = getqtime(ShipQuests_Gugli);
+ mes "val1=" + .@val1;
+ mes "val2=" + .@val2;
+ mes "val3=" + .@val3;
+ mes "valTime=" + .@valTime;
+ .@val1 ++;
+ .@val2 ++;
+ .@val3 ++;
+ .@valTime ++;
+ next;
+ mes "test " + str(.@val1) + ", " + str(.@val2) + ", " + str(.@val3) + ", " + str(.@valTime);
+ setq ShipQuests_Gugli, .@val1, .@val2, .@val3, .@valTime;
+ next;
+ .@val1 = getq(ShipQuests_Gugli);
+ .@val2 = getq2(ShipQuests_Gugli);
+ .@val3 = getq3(ShipQuests_Gugli);
+ .@valTime = getqtime(ShipQuests_Gugli);
+ mes "val1=" + .@val1;
+ mes "val2=" + .@val2;
+ mes "val3=" + .@val3;
+ mes "valTime=" + .@valTime;
+ break;
+ case 6:
+ while(1)
+ {
+ switch (select("add cart:remove cart:back"))
+ {
+ case 1:
+ setcart 1;
+ break;
+ case 2:
+ setcart 0;
+ break;
+ case 3:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 7:
+ while(1)
+ {
+ switch (select("refine", "rent", "bound", "named", "cards", "options", "back"))
+ {
+ case 1:
+ .@item = -1;
+ while(1)
+ {
+ switch (select("set item", "refine +1", "refine -1", "refine fail", "back"))
+ {
+ case 1:
+ .@item = requestitemindex();
+ mes "Item index selected: " + str(.@item);
+ break;
+ case 2:
+ successrefindex .@item, 1;
+ break;
+ case 3:
+ downrefindex .@item, 1;
+ break;
+ case 4:
+ failedrefindex .@item;
+ break;
+ case 5:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 2:
+ while(1)
+ {
+ switch (select("rent vneck for 10 seconds",
+ "rent vneck for 30 seconds",
+ "rent vneck for 1 minute",
+ "rent vneck for 5 minutes",
+ "back"))
+ {
+ case 1:
+ rentitem 1301, 10;
+ break;
+ case 2:
+ rentitem 1301, 30;
+ break;
+ case 3:
+ rentitem 1301, 60;
+ break;
+ case 4:
+ rentitem 1301, 300;
+ break;
+ case 5:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 3:
+ while(1)
+ {
+ switch (select("get bound vneck",
+ "back"))
+ {
+ case 1:
+ getitembound2 1301, 1, 1, 0, 0, 0, 0, 0, 0, 1;
+ break;
+ case 2:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 4:
+ while(1)
+ {
+ switch (select("get named vneck",
+ "back"))
+ {
+ case 1:
+ getnameditem 1301, "4144";
+ break;
+ case 2:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 5:
+ .@item = -1;
+ while(1)
+ {
+ switch (select("set item",
+ "remove cards success",
+ "fail, remove both",
+ "fail, remove card",
+ "fail, remove item",
+ "fail, safe",
+ "print all",
+ "remove 0",
+ "back"))
+ {
+ case 1:
+ .@item = requestitemindex();
+ mes "Item index selected: " + str(.@item);
+ break;
+ case 2:
+ successremovecardsindex .@item;
+ break;
+ case 3:
+ failedremovecardsindex .@item, 0;
+ break;
+ case 4:
+ failedremovecardsindex .@item, 1;
+ break;
+ case 5:
+ failedremovecardsindex .@item, 2;
+ break;
+ case 6:
+ failedremovecardsindex .@item, 3;
+ break;
+ case 7:
+ mes "slots=" + str(MAX_SLOTS);
+ for (.@i = 0; .@i < MAX_SLOTS; .@i++)
+ {
+ mes "slot " + str(.@i) + " = " + str(getcardbyindex(.@item, .@i));
+ }
+ mes "item options:";
+ for (.@i = 0; .@i < 5; .@i ++)
+ {
+ mes sprintf("%d: Option: %d, Value: %d", .@i, getitemoptionidbyindex(.@item, .@i), getitemoptionvaluebyindex(.@item, .@i));
+ }
+ break;
+ case 8:
+ removecardbyindex(.@item, 0);
+ break;
+ case 9:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 6:
+ .@item = -1;
+ while(1)
+ {
+ switch (select("set item", "info", "set option 1", "remove options", "back"))
+ {
+ case 1:
+ .@item = requestitemindex();
+ mes "Item index selected: " + str(.@item);
+ break;
+ case 2:
+ mes "Selected item options";
+ for (.@i = 0; .@i < 5; .@i ++)
+ {
+ mes sprintf("%d: Option: %d, Value: %d", .@i, getitemoptionidbyindex(.@item, .@i), getitemoptionvaluebyindex(.@item, .@i));
+ }
+ break;
+ case 3:
+ setitemoptionbyindex(.@item, 0, VAR_MAXHPAMOUNT, 200);
+ setitemoptionbyindex(.@item, 1, VAR_STRAMOUNT, 10);
+ setitemoptionbyindex(.@item, 2, VAR_VITAMOUNT, -5);
+ break;
+ case 4:
+ mes "Remove item options";
+ for (.@i = 0; .@i < 5; .@i ++)
+ {
+ setitemoptionbyindex(.@item, .@i, 0, 0);
+ }
+ break;
+ case 5:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 7:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 8:
+ chatjoin .chat;
+ close;
+ case 9:
+ while(1)
+ {
+ switch (select("set wall 1:set wall 2:set wall 3:delete wall 1:delete wall 2:delete wall 3:back"))
+ {
+ case 1:
+ setcells "test", 14, 11, 17, 11, 3, "wall1";
+ break;
+ case 2:
+ setcells "test", 14, 7, 21, 8, 1, "wall2";
+ break;
+ case 3:
+ setcells "test", 13, 15, 13, 21, 3, "wall3";
+ break;
+ case 4:
+ delcells "wall1";
+ break;
+ case 5:
+ delcells "wall2";
+ break;
+ case 6:
+ delcells "wall3";
+ break;
+ case 7:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 10:
+ while(1)
+ {
+ switch (select("technical:normal:back"))
+ {
+ case 1:
+ setskin "test2";
+ .@var$ = requestcraft(9);
+ mes .@var$;
+ .@craft = initcraft(.@var$);
+ mes "craft id: " + str(.@craft);
+ mes "is craft valid: " + validatecraft(.@craft);
+ .@id = getcraftslotid(.@craft, 0);
+ .@amount = getcraftslotamount(.@craft, 0);
+ mes "first item id: " + .@id;
+ mes "first item name: " + getitemlink(.@id);
+ mes "first item amount: " + .@amount;
+
+ .@id = getcraftslotid(.@craft, 1);
+ .@amount = getcraftslotamount(.@craft, 1);
+ mes "second item id: " + .@id;
+ mes "second item name: " + getitemlink(.@id);
+ mes "second item amount: " + .@amount;
+// dumpcraft .@craft;
+ .@entry = findcraftentry(.@craft, 0);
+ mes "found craft entry: " + .@entry;
+ if (.@entry < 0)
+ {
+ mes "no craft recipe found";
+ }
+ else
+ {
+ mes "use craft";
+ usecraft .@craft;
+ mes "return code: " + getcraftcode(.@entry);
+ }
+ deletecraft .@craft;
+ setskin "";
+ break;
+ case 2:
+ mes "put items what you want to craft";
+ setskin "test2";
+ .@var$ = requestcraft(9);
+ setskin "";
+ .@craft = initcraft(.@var$);
+ if (.@craft < 0)
+ {
+ mes "Craft error.";
+ goto L_Start;
+ }
+ mes "lets see what you can get...";
+ next;
+ if (!validatecraft(.@craft))
+ {
+ mes "inventory was changed.";
+ goto L_Start;
+ }
+ .@entry = findcraftentry(.@craft, 0);
+ if (.@entry < 0)
+ {
+ mes "no craft recipe found";
+ }
+ else
+ {
+ mes "found recipe";
+ usecraft .@craft;
+ mes "return code: " + getcraftcode(.@entry);
+ }
+ deletecraft .@craft;
+ break;
+ case 3:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 11:
+ switch(select("Create new hashtable",
+ "Use existing ID"))
+ {
+ case 1:
+ .@ht = htnew();
+ mes "ID = " + .@ht;
+ break;
+ case 2:
+ mes "Input ID";
+ input .@ht;
+ break;
+ }
+ .@defval = 0;
+ .@defval_str$ = "";
+ .@newval = 0;
+ .@newval_str$ = "";
+ .@key$ = "";
+
+ while(1)
+ {
+ switch (select("Set default string value",
+ "Set default number value",
+ "Get string",
+ "Get number",
+ "Put string",
+ "Put number",
+ "Show hashtable",
+ "Clear hashtable",
+ "Delete hashtable",
+ "Exit"))
+ {
+ case 1:
+ input .@defval_str$;
+ break;
+ case 2:
+ input .@defval;
+ break;
+ case 3:
+ mes "Input key:";
+ input .@key$;
+ mes "htget(" + .@ht + ", \"" + .@key$ + "\") = " + htget(.@ht, .@key$);
+ mes "htget(" + .@ht + ", \"" + .@key$ + "\", \"" + .@defval_str$ + "\") = " + htget(.@ht, .@key$, .@defval_str$);
+ break;
+ case 4:
+ mes "Input key:";
+ input .@key$;
+ mes "htget(" + .@ht + ", \"" + .@key$ + "\") = " + htget(.@ht, .@key$);
+ mes "htget(" + .@ht + ", \"" + .@key$ + "\", " + .@defval + ") = " + htget(.@ht, .@key$, .@defval);
+ break;
+ case 5:
+ mes "Input key:";
+ input .@key$;
+ mes "Input value:";
+ input .@newval_str$;
+ htput(.@ht, .@key$, .@newval_str$);
+ mes "htput(" + .@ht + ", \"" + .@key$ + "\", \"" + .@newval_str$ + "\")";
+ mes "htget(" + .@ht + ", \"" + .@key$ + "\") = " + htget(.@ht, .@key$);
+ break;
+ case 6:
+ mes "Input key:";
+ input .@key$;
+ mes "Input value:";
+ input .@newval;
+ htput(.@ht, .@key$, .@newval);
+ mes "htput(" + .@ht + ", \"" + .@key$ + "\", " + .@newval + ")";
+ mes "htget(" + .@ht + ", \"" + .@key$ + "\") = " + htget(.@ht, .@key$);
+ break;
+ case 7:
+ mes "size = " + htsize(.@ht);
+ .@hti = htiterator(.@ht);
+ for(.@key$ = htinextkey(.@hti); hticheck(.@hti); .@key$ = htinextkey(.@hti))
+ mes "key = " + .@key$ + " value = " + htget(.@ht, .@key$);
+ htidelete(.@hti);
+ break;
+ case 8:
+ htclear(.@ht);
+ mes "htclear(" + .@ht + ")";
+ break;
+ case 9:
+ htdelete(.@ht);
+ mes "htdelete(" + .@ht + ")";
+ break;
+ case 10:
+ goto L_Start;
+ } // switch
+ } // while
+ break;
+ case 12:
+ while(1)
+ {
+ switch (select("create", "warp", "info", "warp back", "delete", "back"))
+ {
+ case 1:
+ if (.instid >= 0 && isinstance(.instid))
+ {
+ mes "Error: test instance already created";
+ break;
+ }
+// .instid = instance_create("test@instance", 0, 0);
+ .instid = instance_create("test@instance", getcharid(3), IOT_CHAR);
+ if (.instid < 0)
+ {
+ mes "Error: creating instance";
+ break;
+ }
+ mes "new instance id: " + str(.instid);
+// .@instanceMapName$ = instance_attachmap("test", .instid, 1, "test@map1");
+// .@instanceMapName$ = instance_attachmap("test", .instid, 1);
+ .@instanceMapName$ = instance_attachmap("test", .instid, 0, "test@map1");
+ if (.@instanceMapName$ == "")
+ {
+ mes "Error: instance attach map error";
+ break;
+ }
+ mes "Attached instance map name: " + .@instanceMapName$;
+ instance_set_timeout(1000000, 1000000, .instid);
+ instance_init(.instid);
+ break;
+ case 2:
+ warp "test@map1", 12, 12;
+ break;
+ case 3:
+ mes "npc name: " + .name$;
+ mes "npc ext name: " + .extname$;
+ mes "npc id: " + .id;
+ mes "npc parent id: " + .parent;
+ mes "npc src id: " + .srcId;
+ if (instance_id() >= 0)
+ {
+ mes "npc1 in instance named: " + instance_npcname("npc1");
+ }
+ else
+ {
+ mes "npc1 not in instance";
+ }
+ break;
+ case 4:
+ warp "test", 12, 12;
+ break;
+ case 5:
+ if (.instid < 0)
+ {
+ mes "Error: test instance was not created";
+ break;
+ }
+ instance_destroy(.instid);
+ break;
+ case 6:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 13:
+ while(1)
+ {
+ switch (select("create mercenary for 10 seconds", "create mercenary for 1 min", "create mercenary for 10 min", "back"))
+ {
+ case 1:
+ mercenary_create 1191, 10000;
+ break;
+ case 2:
+ mercenary_create 1191, 60000;
+ break;
+ case 3:
+ mercenary_create 1191, 600000;
+ break;
+ case 4:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 14:
+ while(1)
+ {
+ switch (select("set hair 1", "set hair 0", "equip vneck", "unequip vneck", "back"))
+ {
+ case 1:
+ setunitdata(.@npcId, UDT_HAIRSTYLE, 5);
+ setunitdata(.@npcId, UDT_HAIRCOLOR, 17);
+ break;
+ case 2:
+ .@npcId = getnpcid("npc4");
+ setunitdata(.@npcId, UDT_HAIRSTYLE, 0);
+ break;
+ case 3:
+ .@npcId = getnpcid("npc4");
+ setunitdata(.@npcId, UDT_HEADTOP, 1301);
+ break;
+ case 4:
+ .@npcId = getnpcid("npc4");
+ setunitdata(.@npcId, UDT_HEADTOP, 0);
+ break;
+ case 5:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ case 15:
+ while(1)
+ {
+ switch (select(
+ "join sword clan",
+ "join arc wand clan",
+ "join golden mace clan",
+ "join crossbox clan",
+ "leave clan",
+ "back"))
+ {
+ case 1:
+ mes(str(clan_join(1)));
+ break;
+ case 2:
+ mes(str(clan_join(2)));
+ break;
+ case 3:
+ mes(str(clan_join(3)));
+ break;
+ case 4:
+ mes(str(clan_join(4)));
+ break;
+ case 5:
+ mes(str(clan_leave()));
+ break;
+ case 6:
+ goto L_Start;
+ break;
+ }
+ }
+ break;
+ }
+
+ close;
+
+OnTouch:
+ doorTouch;
+
+OnUnTouch:
+ doorUnTouch;
+
+OnTimer340:
+ doorTimer;
+
+OnInit:
+ .distance = 5;
+ .alwaysVisible = true;
+ waitingroom "test room", 2, "npc1::OnReadyCheck", 1;
+ // test instance id
+ .instid = -10;
+ if (.parent != 0)
+ {
+ setnpcdir 0;
+ }
+ end;
+
+OnWhisperGlobal:
+ mes "cmd: " + @whispervar0$;
+ close;
+
+OnReadyCheck:
+ consolemes(CONSOLEMES_DEBUG, "OnReadyCheck");
+ $@bgid1 = waitingroom2bg("testbg", 10, 10, "bgnpc1::OnLogout","bgnpc1:OnDie");
+ consolemes(CONSOLEMES_DEBUG, "bgid=" + str($@bgid1));
+ setbgteam $@bgid1, 1;
+ bg_warp $@bgid1, "testbg", 10, 10;
+}
diff --git a/npc/test/npc2.txt b/npc/test/npc2.txt
new file mode 100644
index 00000000..8a2146f1
--- /dev/null
+++ b/npc/test/npc2.txt
@@ -0,0 +1,35 @@
+// Evol scripts.
+// Author:
+// 4144
+// Description:
+// test npc2
+
+test,20,10,0 trader npc2 NPC_HAT_BOX,{
+OnInit:
+ tradertype(NST_MARKET);
+ sellitem 505, -1, 10;
+ sellitem 502, -1, 10;
+ sellitem 513, -1, 10;
+ sellitem 509, -1, 10;
+ sellitem 2000, -1, 10;
+ sellitem 1800, -1, 10;
+ sellitem 3501, -1, 10;
+ end;
+
+OnClock0000:
+ if (shopcount(505) < 10)
+ sellitem 505, -1, 10;
+ if (shopcount(502) < 10)
+ sellitem 502, -1, 10;
+ if (shopcount(513) < 10)
+ sellitem 513, -1, 10;
+ if (shopcount(509) < 10)
+ sellitem 509, -1, 10;
+ if (shopcount(2000) < 10)
+ sellitem 2000, -1, 10;
+ if (shopcount(1800) < 10)
+ sellitem 1800, -1, 10;
+ if (shopcount(3501) < 10)
+ sellitem 3501, -1, 10;
+ end;
+}
diff --git a/npc/test/npc3.txt b/npc/test/npc3.txt
new file mode 100644
index 00000000..82d5fe3f
--- /dev/null
+++ b/npc/test/npc3.txt
@@ -0,0 +1,7 @@
+// Evol scripts.
+// Author:
+// 4144
+// Description:
+// test npc3
+
+test,25,10,0 cashshop npc3 NPC_SHOP_BAG,505:100,502:-1,513:-1,509:-1,2000:-1,1800:-1,3501:-1
diff --git a/npc/test/npc4.txt b/npc/test/npc4.txt
new file mode 100644
index 00000000..b85d1bf8
--- /dev/null
+++ b/npc/test/npc4.txt
@@ -0,0 +1,30 @@
+// Evol scripts.
+// Author:
+// 4144
+// Description:
+// test npc4
+
+test,25,20,0 script npc4 NPC_PLAYER,{
+ close;
+OnTimer1000:
+ domovestep;
+OnInit:
+ .walkmask = WALK_WATER;
+ initpath "move", 20, 20,
+ "sit", 0, 0,
+ "dir", 6, 0,
+ "move", 25, 20,
+ "emote", 3, 0,
+// "class", 104, 0,
+ "speed", 100, 0,
+ "wait", 2, 0,
+ "move", 22, 10,
+ "rmove", 3, 3,
+// "class", 801, 0,
+ "speed", 200, 0,
+ "wait", 1, 0,
+ "warp", 22, 30,
+ "goto", 0, 0;
+ initialmove;
+ initnpctimer;
+}
diff --git a/npc/test/npc5.txt b/npc/test/npc5.txt
new file mode 100644
index 00000000..faa655e8
--- /dev/null
+++ b/npc/test/npc5.txt
@@ -0,0 +1,34 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Description:
+// test npc5
+
+function script npc5TestFunc {
+ npctalk getarg(0);
+ return 0;
+}
+
+test,45,25,0 script npc5 NPC_PLAYER,{
+ close;
+
+OnTimer1000:
+ dographmovestep;
+
+OnInit:
+ // .debug = 1;
+ initmovegraph "topleft", 45, 25,
+ "topright", 55, 25,
+ "bottomright", 55, 34,
+ "bottomleft", 45, 34;
+
+ setmovegraphcmd "topleft", "topright", 30, "dir 0; wait 1",
+ "topleft", "bottomright", 20, "class 104",
+ "topleft", "bottomleft", 50, "emote 8; wait 1; warp bottomright",
+ "topright", "bottomleft", 1, "emote 3; wait 5",
+ "bottomleft", "topleft", 25, "dir 2; wait 1; call npc5TestFunc Hello=)",
+ "bottomleft", "bottomright", 10, "speed 40",
+ "bottomright", "bottomleft", 1, "class 801; speed 100; dir 0; emote 1; wait 4";
+ firstmove "wait 1; speed 100; dir 4; emote 7";
+ initnpctimer;
+}
diff --git a/npc/test/npc6.txt b/npc/test/npc6.txt
new file mode 100644
index 00000000..7c4893ad
--- /dev/null
+++ b/npc/test/npc6.txt
@@ -0,0 +1,23 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Description:
+// test npc1
+
+test,30,10,0 trader npc6 NPC_SHOP_BAG_TEST,{
+ end;
+
+OnCountFunds:
+ setcurrency 10000;
+ end;
+
+OnPayFunds:
+ dispbottom "Hi: price="+@price+" and points="+@points;
+ // check and remove points
+ purchaseok;
+ end;
+OnInit:
+ tradertype NST_CUSTOM;
+ sellitem Acorn, 500;
+ sellitem Bread, 200;
+}
diff --git a/npc/test/test1.txt b/npc/test/test1.txt
new file mode 100644
index 00000000..9fefe307
--- /dev/null
+++ b/npc/test/test1.txt
@@ -0,0 +1,165 @@
+// Evol scripts.
+// Author:
+// 4144
+// Description:
+// script tests
+
+function script test1function {
+ .var = .walkmask;
+ if (.var != 3)
+ mes "Error: testing test1 npc variables from function.";
+ .var = getvariableofnpc(.walkmask, "test1");
+ if (.var != 3)
+ mes "Error: testing test1 npc variables from function.";
+ .var = getvariableofnpc(.walkmask, "test2");
+ if (.var != 4)
+ mes "Error: testing test2 npc variables from function.";
+
+ return;
+}
+
+test,10,5,0 script test1 NPC_HAT_BOX,{
+
+ function assert {
+ if (getarg(0)) {
+ .stats[1]++;
+ // comment out the next line for less verbosity
+ mesf("Success: %s.", getarg(1));
+ } else {
+ mesf("##BError##b: %s.", getarg(1));
+ }
+ return .stats[0]++;
+ }
+
+ function test_npc_vars {
+ mes("##2Testing NPC variables...##0");
+ .var = .walkmask;
+ assert(.var == 3, "test1 npc variales");
+ .var = getvariableofnpc(.walkmask, "test1");
+ assert(.var == 3, "test1 npc variables from function");
+ .var = getvariableofnpc(.walkmask, "test2");
+ assert(.var == 4, "test2 npc variables");
+ test1function();
+ next();
+ }
+
+ function test_quest_vars {
+ mes("##2Testing quest variables...##0");
+ .@time = 1000;
+ setq(Test_testing1, 1, 2, 3, .@time);
+ assert(getq(Test_testing1) == 1, "getq1 = 1");
+ assert(getq2(Test_testing1) == 2, "getq2 = 2");
+ assert(getq3(Test_testing1) == 3, "getq3 = 3");
+ assert(getqtime(Test_testing1) == .@time, "getqtime = 1000");
+ next();
+ .@time = 2000;
+ setq(Test_testing1, 2, 3, 4, .@time);
+ assert(getq(Test_testing1) == 2, "getq1 = 2");
+ assert(getq2(Test_testing1) == 3, "getq2 = 3");
+ assert(getq3(Test_testing1) == 4, "getq3 = 4");
+ assert(getqtime(Test_testing1) == .@time, "getqtime = 2000");
+ next();
+ setq(Test_testing1, 0);
+ }
+
+ function test_translation_old {
+ mes("##2Testing old translation system without gender...##0");
+ assert(l("test @@", "") == "test ", "\"test @@\", \"\"");
+ assert(l("test @@", "foo") == "test foo", "\"test @@\", \"foo\"");
+ assert(l("@@", "") == "", "\"@@\", \"\"");
+ assert(l("@@") == "@@", "\"@@\"");
+ assert(l("@@ @@ @@", "this", "is", "test") == "this is test", "\"@@ @@ @@\", \"this\", \"is\", \"test\"");
+ assert(l("data @@ @@ @@ data", "this", "is", "test") == "data this is test data", "\"data @@ @@ @@ data\", \"this\", \"is\", \"test\"");
+ next();
+
+ /*
+ mesf("##2Testing old translation system as %s gender...##0", g("female", "male"));
+ if (Sex == 1)
+ assert(lg("test1 @@", "test2 @@", "line") == "test2 line#1", "\"test1 @@\", \"test2 @@\", \"line\"");
+ else if (Sex == 0)
+ assert(lg("test1 @@", "test2 @@", "line") == "test1 line#0", "\"test1 @@\", \"test2 @@\", \"line\"");
+ */
+ next();
+ }
+
+ function test_translation_new {
+ mes("##2Testing new translation system without gender...##0");
+ assert(l("") == "", "\"\"");
+ assert(l("test") == "test", "\"test\"");
+ assert(l("test %s", "") == "test ", "\"test %s\", \"\"");
+ assert(l("test %s", "foo") == "test foo", "\"test %s\", \"foo\"");
+ assert(l("%s", "") == "", "\"%s\", \"\"");
+ assert(l("%s") == "%s", "\"%s\"");
+ assert(l("%%") == "%%", "\"%##0%\""); // XXX: %% is reserved for emotes in manaplus, so we escape it with color
+ assert(l("%d%%", 6) == "6%", "\"%d%##0%\", 6"); // XXX: %% is reserved for emotes in manaplus, so we escape it with color
+ assert(l("%s %s %s", "this", "is", "test") == "this is test", "\"%s %s %s\", \"this\", \"is\", \"test\"");
+ assert(l("%s %d %s", "foo", 69, "bar") == "foo 69 bar", "\"%s %d %s\", \"foo\", 69, \"bar\"");
+ assert(l("data %s %s %s data", "this", "is", "test") == "data this is test data", "\"data %s %s %s data\", \"this\", \"is\", \"test\"");
+ next();
+
+ /*
+ mesf("##2Testing new translation system as %s gender...##0", g("female", "male"));
+ if (Sex == 1) {
+ assert(lg("test") == "test#1", "\"test\"");
+ assert(lg("test1", "test2") == "test2#1", "\"test1\", \"test2\"");
+ assert(lg("test1 %s", "test2 %s", "line") == "test2 line#1", "\"test1 %s\", \"test2 %s\", \"line\"");
+ } else if (Sex == 0) {
+ assert(lg("test") == "test#0", "\"test\"");
+ assert(lg("test1", "test2") == "test1#0", "\"test1\", \"test2\"");
+ assert(lg("test1 %s", "test2 %s", "line") == "test1 line#0", "\"test1 %s\", \"test2 %s\", \"line\"");
+ }
+ */
+ next();
+
+ mes("##2Testing advanced translation...##0");
+ assert(l("foo %2$s bar %1$s baz", "qux", "quux") == "foo quux bar qux baz", "\"foo %2$s bar %1$s baz\", \"qux\", \"quux\"");
+ assert(l("%5d", 6) == " 6", "\"%5d\", 6");
+ assert(l("%5d", -6) == " -6", "\"%5d\", -6");
+ assert(l("%+5d", 6) == " +6", "\"%+5d\", 6");
+ assert(l("%+5d", -6) == " -6", "\"%+5d\", -6");
+ assert(l("%-5d", 6) == "6 ", "\"%-5d\", 6");
+ assert(l("%-5d", -6) == "-6 ", "\"%-5d\", -6");
+ assert(l("% 5d", 6) == " 6", "\"% 5d\", 6");
+ assert(l("% 5d", -6) == " -6", "\"% 5d\", -6");
+ assert(l("%05d", 6) == "00006", "\"%05d\", 6");
+ assert(l("%05d", -6) == "-0006", "\"%05d\", -6");
+ assert(l("%10s", "test") == " test", "\"%10s\", \"test\"");
+ assert(l("% 10s", "test") == " test", "\"% 10s\", \"test\"");
+ assert(l("%-10s", "test") == "test ", "\"%-10s\", \"test\"");
+ next();
+ }
+
+
+ do {
+ mes("Please select a test:");
+ select(
+ "NPC variables",
+ "quest variables",
+ "translation (old)",
+ "translation (new)",
+ "everything");
+
+ setarray(.stats[0], 0, 0); // make sure we have a clean state
+ clear();
+
+ switch (@menu) {
+ case 1: test_npc_vars(); break;
+ case 2: test_quest_vars(); break;
+ case 3: test_translation_old(); break;
+ case 4: test_translation_new(); break;
+ default:
+ test_translation_old();
+ test_translation_new();
+ test_npc_vars();
+ test_quest_vars();
+ }
+
+ mesf("##BTests complete. [%02d/%02d]", .stats[1], .stats[0]);
+ next();
+ } while (true);
+ close;
+
+OnInit:
+ .walkmask = 3;
+ end;
+}
diff --git a/npc/test/test2.txt b/npc/test/test2.txt
new file mode 100644
index 00000000..fdc6f847
--- /dev/null
+++ b/npc/test/test2.txt
@@ -0,0 +1,13 @@
+// Evol scripts.
+// Author:
+// 4144
+// Description:
+// script tests
+
+test,12,5,0 script test2 NPC_HAT_BOX,{
+ close;
+
+OnInit:
+ .walkmask = 4;
+ end;
+}
diff --git a/npc/testbg/_import.txt b/npc/testbg/_import.txt
new file mode 100644
index 00000000..c8affdf4
--- /dev/null
+++ b/npc/testbg/_import.txt
@@ -0,0 +1,3 @@
+// Map testbg: testbg
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/testbg/mapflags.txt",
diff --git a/npc/testbg/mapflags.txt b/npc/testbg/mapflags.txt
new file mode 100644
index 00000000..764a55df
--- /dev/null
+++ b/npc/testbg/mapflags.txt
@@ -0,0 +1 @@
+testbg mapflag battleground