最终整理版
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
extends NpcScript
|
||||
|
||||
const questID : int = ProgressCommons.Quest.SNAKE_PIT_THIEF
|
||||
const bitIndex : int = 0
|
||||
var thiefsKeyID : int = DB.GetCellHash("Thief's Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var state : int = GetQuest(questID)
|
||||
if state >= ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED:
|
||||
return
|
||||
|
||||
Mes("墙上刻着第一行字:我从图利姆沙偷走的不是金子,而是一条能让我活下去的路。")
|
||||
Mes("字迹旁画着一只蛇,蛇头朝北。")
|
||||
|
||||
var newState : int = state | (1 << bitIndex)
|
||||
if newState != state:
|
||||
SetQuest(questID, newState)
|
||||
|
||||
if newState == ProgressCommons.SNAKE_PIT_THIEF.ALL_CLUES_FOUND:
|
||||
OnAllCluesFound()
|
||||
|
||||
func OnAllCluesFound():
|
||||
SetQuest(questID, ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED)
|
||||
AddItem(thiefsKeyID, 1)
|
||||
Mes("五行刻字在你脑海中拼成完整的路线。石缝弹开,你找到一把盗贼钥匙。")
|
||||
@@ -0,0 +1,26 @@
|
||||
extends NpcScript
|
||||
|
||||
const questID : int = ProgressCommons.Quest.SNAKE_PIT_THIEF
|
||||
const bitIndex : int = 1
|
||||
var thiefsKeyID : int = DB.GetCellHash("Thief's Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var state : int = GetQuest(questID)
|
||||
if state >= ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED:
|
||||
return
|
||||
|
||||
Mes("墙上刻着第二行字:沙会吞掉脚印,水会记住脚步。")
|
||||
Mes("字迹下方有几道短线,像是在提醒你数清岔路。")
|
||||
|
||||
var newState : int = state | (1 << bitIndex)
|
||||
if newState != state:
|
||||
SetQuest(questID, newState)
|
||||
|
||||
if newState == ProgressCommons.SNAKE_PIT_THIEF.ALL_CLUES_FOUND:
|
||||
OnAllCluesFound()
|
||||
|
||||
func OnAllCluesFound():
|
||||
SetQuest(questID, ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED)
|
||||
AddItem(thiefsKeyID, 1)
|
||||
Mes("五行刻字在你脑海中拼成完整的路线。石缝弹开,你找到一把盗贼钥匙。")
|
||||
@@ -0,0 +1,26 @@
|
||||
extends NpcScript
|
||||
|
||||
const questID : int = ProgressCommons.Quest.SNAKE_PIT_THIEF
|
||||
const bitIndex : int = 2
|
||||
var thiefsKeyID : int = DB.GetCellHash("Thief's Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var state : int = GetQuest(questID)
|
||||
if state >= ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED:
|
||||
return
|
||||
|
||||
Mes("墙上刻着第三行字:若听见鳞片摩擦石头,就别拔刀;停下,等它先走。")
|
||||
Mes("刻字边缘被蛇鳞磨得发亮,像是很多年都没有真正安静过。")
|
||||
|
||||
var newState : int = state | (1 << bitIndex)
|
||||
if newState != state:
|
||||
SetQuest(questID, newState)
|
||||
|
||||
if newState == ProgressCommons.SNAKE_PIT_THIEF.ALL_CLUES_FOUND:
|
||||
OnAllCluesFound()
|
||||
|
||||
func OnAllCluesFound():
|
||||
SetQuest(questID, ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED)
|
||||
AddItem(thiefsKeyID, 1)
|
||||
Mes("五行刻字在你脑海中拼成完整的路线。石缝弹开,你找到一把盗贼钥匙。")
|
||||
@@ -0,0 +1,26 @@
|
||||
extends NpcScript
|
||||
|
||||
const questID : int = ProgressCommons.Quest.SNAKE_PIT_THIEF
|
||||
const bitIndex : int = 3
|
||||
var thiefsKeyID : int = DB.GetCellHash("Thief's Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var state : int = GetQuest(questID)
|
||||
if state >= ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED:
|
||||
return
|
||||
|
||||
Mes("墙上刻着第四行字:我把宝箱留给能读懂害怕的人。贪心的人只会听见锁声。")
|
||||
Mes("这里的沙子很新,似乎有人不久前才翻动过。")
|
||||
|
||||
var newState : int = state | (1 << bitIndex)
|
||||
if newState != state:
|
||||
SetQuest(questID, newState)
|
||||
|
||||
if newState == ProgressCommons.SNAKE_PIT_THIEF.ALL_CLUES_FOUND:
|
||||
OnAllCluesFound()
|
||||
|
||||
func OnAllCluesFound():
|
||||
SetQuest(questID, ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED)
|
||||
AddItem(thiefsKeyID, 1)
|
||||
Mes("五行刻字在你脑海中拼成完整的路线。石缝弹开,你找到一把盗贼钥匙。")
|
||||
@@ -0,0 +1,26 @@
|
||||
extends NpcScript
|
||||
|
||||
const questID : int = ProgressCommons.Quest.SNAKE_PIT_THIEF
|
||||
const bitIndex : int = 4
|
||||
var thiefsKeyID : int = DB.GetCellHash("Thief's Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var state : int = GetQuest(questID)
|
||||
if state >= ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED:
|
||||
return
|
||||
|
||||
Mes("墙上刻着最后一行字:北、东、静候、回头,再向没有风的地方走。")
|
||||
Mes("最后一个字下面压着一块松动的石片。")
|
||||
|
||||
var newState : int = state | (1 << bitIndex)
|
||||
if newState != state:
|
||||
SetQuest(questID, newState)
|
||||
|
||||
if newState == ProgressCommons.SNAKE_PIT_THIEF.ALL_CLUES_FOUND:
|
||||
OnAllCluesFound()
|
||||
|
||||
func OnAllCluesFound():
|
||||
SetQuest(questID, ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED)
|
||||
AddItem(thiefsKeyID, 1)
|
||||
Mes("五行刻字在你脑海中拼成完整的路线。石缝弹开,你找到一把盗贼钥匙。")
|
||||
@@ -0,0 +1,64 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(WaterPondGlobal.QUEST_ID):
|
||||
ProgressCommons.SNAKE_PIT_BITING_THIRST.INACTIVE:
|
||||
OnInactive()
|
||||
ProgressCommons.SNAKE_PIT_BITING_THIRST.STARTED:
|
||||
OnCheckProgress()
|
||||
ProgressCommons.SNAKE_PIT_BITING_THIRST.REWARDS_WITHDREW:
|
||||
OnComplete()
|
||||
_:
|
||||
OnInProgress()
|
||||
|
||||
# Quest states
|
||||
func OnInactive():
|
||||
Mes("我的水全洒了。没有水,我回不到图利姆沙。")
|
||||
Mes("几天前我以为自己能征服这片沙地,就进了这座洞。里面有一处很干净的地下水池,以前旅人会来这里补水。")
|
||||
Mes("后来蛇越来越多。它们毒性不强,但咬得很凶,我每次装好水,走不到一半就被咬到手抖,把水全洒掉。")
|
||||
Mes("你能替我试一次吗?只要把水罐装满带回来,我就能回城。")
|
||||
Mes("洞里还有些旧刻字,像是某个盗贼留下的路线。你如果看见,最好记下来,蛇坑里没有无用的线索。")
|
||||
Choice("我去试试。", OnAccept)
|
||||
Choice("今天不行。", OnDecline)
|
||||
|
||||
func OnCheckProgress():
|
||||
var rid : int = own.get_rid().get_id()
|
||||
if WaterPondGlobal.biteCounters.get(rid, 0) == 0:
|
||||
OnInProgress()
|
||||
else:
|
||||
OnDeliverWater()
|
||||
|
||||
func OnInProgress():
|
||||
Mes("清水池在洞穴深处,不是每一处水都能喝,脏水只会害你白跑。")
|
||||
Mes("找到清水池后别乱动,等水罐装满,再尽快带回来。")
|
||||
Mes("路上被蛇咬会漏水。漏光了就回水池重新装,别拿空罐子回来安慰我。")
|
||||
|
||||
func OnDeliverWater():
|
||||
WaterPondGlobal.StopJugTransport(own)
|
||||
ClearTracker()
|
||||
Mes("你回来了!水还在,太好了。")
|
||||
Mes("拿着这些,这是我剩下的东西。比不上你救我一命,但至少能让你少受点苦。")
|
||||
SetQuest(WaterPondGlobal.QUEST_ID, ProgressCommons.SNAKE_PIT_BITING_THIRST.REWARDS_WITHDREW)
|
||||
AddItem(DB.GetCellHash("Cactus Drink"), 10)
|
||||
AddExp(50)
|
||||
AddGP(1000)
|
||||
AddKarma(1)
|
||||
Mes("我现在就回图利姆沙。这里太危险了。")
|
||||
Mes("以后我会乖乖用城里的井水。蛇坑里的水,就留给蛇和胆子太大的人吧。")
|
||||
|
||||
func OnComplete():
|
||||
Mes("谢谢你帮我取回那罐水。现在我可以慢慢走回城,不用每一步都想着自己会不会倒下。")
|
||||
Mes("沙漠很美,但我已经受够了它的待客方式。")
|
||||
|
||||
func OnDecline():
|
||||
Mes("我明白。要是你改变主意,我还会在这里,希望不会太久。")
|
||||
|
||||
# Transitions
|
||||
func OnAccept():
|
||||
SetQuest(WaterPondGlobal.QUEST_ID, ProgressCommons.SNAKE_PIT_BITING_THIRST.STARTED)
|
||||
Mes("拿着这个水罐。清水池在洞穴深处。")
|
||||
Mes("我只记得一开始往北,之后转向东边。再后面也许是向南,也许是追着没有风的地方走。")
|
||||
Mes("说实话,我记得最清楚的是蛇咬上来的声音。")
|
||||
Mes("如果你在墙上看到旧盗贼的刻字,就照着记。那些字也许比我的脑袋可靠。")
|
||||
Mes("最好带上可靠的宠物伙伴。蛇很多,单靠胆量装不满水。")
|
||||
@@ -0,0 +1,40 @@
|
||||
extends NpcScript
|
||||
|
||||
# Quest ID
|
||||
const questID : int = ProgressCommons.Quest.SNAKE_PIT_THIEF
|
||||
|
||||
# Reward items
|
||||
var scimitarID : int = DB.GetCellHash("Scimitar")
|
||||
|
||||
# Required items
|
||||
var thiefsKeyID : int = DB.GetCellHash("Thief's Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(questID):
|
||||
ProgressCommons.SNAKE_PIT_THIEF.RIDDLE_SOLVED: OnTryOpen()
|
||||
ProgressCommons.SNAKE_PIT_THIEF.REWARDS_WITHDREW: OnEmpty()
|
||||
_: OnLocked()
|
||||
|
||||
func OnTryOpen():
|
||||
if not HasItem(thiefsKeyID):
|
||||
OnLocked()
|
||||
return
|
||||
|
||||
if not IsTriggering():
|
||||
Trigger()
|
||||
|
||||
Mes("五条刻字指向的锁孔终于转动。箱盖掀开时,一股干冷的旧沙味涌了出来。")
|
||||
SetQuest(questID, ProgressCommons.SNAKE_PIT_THIEF.REWARDS_WITHDREW)
|
||||
|
||||
RemoveItem(thiefsKeyID, 1)
|
||||
AddGP(200)
|
||||
AddItem(scimitarID, 1)
|
||||
AddExp(50)
|
||||
AddKarma(2)
|
||||
|
||||
func OnEmpty():
|
||||
Chat("盗贼宝箱已经空了,只剩几道被蛇鳞刮出的细痕。")
|
||||
|
||||
func OnLocked():
|
||||
Chat("箱锁上刻着蛇形纹路。没有盗贼钥匙,打不开它。")
|
||||
@@ -0,0 +1,13 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(WaterPondGlobal.QUEST_ID):
|
||||
ProgressCommons.SNAKE_PIT_BITING_THIRST.STARTED:
|
||||
OnFill()
|
||||
|
||||
func OnFill():
|
||||
var rid : int = own.get_rid().get_id()
|
||||
if not WaterPondGlobal.biteCounters.has(rid) and npc.get_node_or_null(own.nick) == null:
|
||||
(npc.ownScript as WaterPondGlobal).OnFillTick(own, own.position, 0)
|
||||
Mes("你把水罐浸入清水池。先别动,等水慢慢装满。")
|
||||
@@ -0,0 +1,6 @@
|
||||
extends NpcScript
|
||||
|
||||
func OnStart():
|
||||
match GetQuest(WaterPondGlobal.QUEST_ID):
|
||||
ProgressCommons.SNAKE_PIT_BITING_THIRST.STARTED:
|
||||
Mes("这池水混着泥和蛇蜕,绝不是毛罗说的清水池。")
|
||||
@@ -0,0 +1,67 @@
|
||||
extends NpcScript
|
||||
class_name WaterPondGlobal
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.SNAKE_PIT_BITING_THIRST
|
||||
const MAX_BITES : int = 5
|
||||
const FILL_TIME : float = 5.0
|
||||
const FILL_TICKS : int = 10
|
||||
const FILL_TICK_TIME : float = FILL_TIME / FILL_TICKS
|
||||
const MOVE_TOLERANCE_SQUARED : float = 8.0 * 8.0
|
||||
|
||||
# Per-player bite counters [PlayerRID, BiteCount]
|
||||
static var biteCounters : Dictionary[int, int] = {}
|
||||
|
||||
# Signal handling
|
||||
static func StartJugTransport(player : PlayerAgent):
|
||||
var rid : int = player.get_rid().get_id()
|
||||
biteCounters[rid] = MAX_BITES
|
||||
if not player.agent_damaged.is_connected(OnBite):
|
||||
player.agent_damaged.connect(OnBite)
|
||||
|
||||
static func StopJugTransport(player : PlayerAgent):
|
||||
var rid : int = player.get_rid().get_id()
|
||||
biteCounters.erase(rid)
|
||||
if player.agent_damaged.is_connected(OnBite):
|
||||
player.agent_damaged.disconnect(OnBite)
|
||||
|
||||
# Biting handling
|
||||
static func OnBite(player : PlayerAgent, value : int):
|
||||
if value == 0 or player.progress.GetQuest(QUEST_ID) != ProgressCommons.SNAKE_PIT_BITING_THIRST.STARTED:
|
||||
return
|
||||
|
||||
var rid : int = player.get_rid().get_id()
|
||||
if not biteCounters.has(rid):
|
||||
return
|
||||
|
||||
var remaining : int = biteCounters[rid] - 1
|
||||
biteCounters[rid] = remaining
|
||||
NpcCommons.PushTracker(player, "水罐完整度", remaining, MAX_BITES, "%")
|
||||
if remaining <= 0:
|
||||
Spill(player)
|
||||
|
||||
static func Spill(player : PlayerAgent):
|
||||
StopJugTransport(player)
|
||||
NpcCommons.SetQuest(player, QUEST_ID, ProgressCommons.SNAKE_PIT_BITING_THIRST.STARTED)
|
||||
NpcCommons.ClearTracker(player)
|
||||
NpcCommons.PushNotification(player, "你被蛇咬得太多,水罐漏空了。回清水池重新装水。")
|
||||
|
||||
# Jug filling handling
|
||||
func OnFillTick(player : PlayerAgent, startPos : Vector2, tick : int):
|
||||
if player.position.distance_squared_to(startPos) > MOVE_TOLERANCE_SQUARED:
|
||||
NpcCommons.ClearTracker(player)
|
||||
NpcCommons.PushNotification(player, "你动得太早,水还没装满。")
|
||||
else:
|
||||
if tick >= FILL_TICKS:
|
||||
CompleteFill(player)
|
||||
else:
|
||||
NpcCommons.PushTracker(player, "正在装水", tick, FILL_TICKS, "%")
|
||||
ScheduleTick(player, startPos, tick)
|
||||
|
||||
func ScheduleTick(player : PlayerAgent, startPos : Vector2, tick : int):
|
||||
AddTimer(own, FILL_TICK_TIME, OnFillTick.bind(player, startPos, tick + 1), player.nick)
|
||||
|
||||
func CompleteFill(player : PlayerAgent):
|
||||
StartJugTransport(player)
|
||||
NpcCommons.PushTracker(player, "水罐完整度", MAX_BITES, MAX_BITES, "%")
|
||||
NpcCommons.PushNotification(player, "水罐装满了,尽快带回毛罗。")
|
||||
@@ -0,0 +1,39 @@
|
||||
extends NpcScript
|
||||
|
||||
# Quest ID
|
||||
const questID : int = ProgressCommons.Quest.SANDSTORM_MINE_ABANDONED_TREASURE
|
||||
|
||||
# Required items
|
||||
var chestMineKeyID : int = DB.GetCellHash("Chest Mine Key")
|
||||
|
||||
# Reward items
|
||||
var shortSwordID : int = DB.GetCellHash("Short Sword")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(questID):
|
||||
ProgressCommons.SANDSTORM_MINE_ABANDONED_TREASURE.KEY_FOUND: OnTryOpen()
|
||||
ProgressCommons.SANDSTORM_MINE_ABANDONED_TREASURE.REWARDS_WITHDREW: OnEmpty()
|
||||
_: OnLocked()
|
||||
|
||||
func OnTryOpen():
|
||||
if not HasItem(chestMineKeyID):
|
||||
OnLocked()
|
||||
return
|
||||
|
||||
if not IsTriggering():
|
||||
Trigger()
|
||||
|
||||
if HasSpace(1):
|
||||
Mes("钥匙插进锁孔后,锈住的机关咔哒一声松开。箱子里还躺着一把矿工留下的短剑。")
|
||||
RemoveItem(chestMineKeyID, 1)
|
||||
SetQuest(questID, ProgressCommons.SANDSTORM_MINE_ABANDONED_TREASURE.REWARDS_WITHDREW)
|
||||
AddItem(shortSwordID, 1)
|
||||
else:
|
||||
Mes("你找到了能打开箱子的钥匙,但背包已经装不下新的武器。")
|
||||
|
||||
func OnEmpty():
|
||||
Chat("箱子已经空了,只剩下矿砂和木屑。")
|
||||
|
||||
func OnLocked():
|
||||
Chat("矿工留下的旧箱子锁着,需要对应的矿洞钥匙。")
|
||||
@@ -0,0 +1,13 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("你就是艾基努派来的侦察员?看起来还站得稳,这已经比我预想的好。")
|
||||
Mes("别误会,艾基努不是想害你。他只是知道矿洞里需要一个会随机应变的人。")
|
||||
|
||||
Mes("从这里往东南走,旧井旁边就是沙漠风暴矿洞入口。")
|
||||
Mes("如果你一路走到谷地外面,说明方向错了;真正的入口不会离风声太远。")
|
||||
Mes("看守内森应该在入口站岗。他话多,但眼睛不瞎,能帮你确认矿洞情况。")
|
||||
Mes("我们的几个人已经先进去了。你进去后先确认路线,再判断哪些宠物和怪物能避开,哪些必须处理。")
|
||||
|
||||
Mes("祝你好运。还有,别为了证明胆量去碰看起来会发光的东西。")
|
||||
@@ -0,0 +1,9 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const mapPos : Vector2i = Vector2i(1760, 2560)
|
||||
var mapName : int = "Desert Deep Level".hash()
|
||||
|
||||
#
|
||||
func OnAreaEnter(player : PlayerAgent):
|
||||
NpcCommons.WarpInstance(player, mapName, mapPos)
|
||||
@@ -0,0 +1,20 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("从那条西侧山口继续走,就会离开 图利姆沙谷地,进入 祖尼石台地。")
|
||||
Mes("那里路标少、岩影多,第一次去的人常常把回头路也弄丢。你确定方向吗?")
|
||||
Choice("我在找 沙漠风暴矿洞。", OnMines)
|
||||
Choice("我想回 图利姆沙。", OnTulimshar)
|
||||
|
||||
func OnMines():
|
||||
LookAtNpc("To Mines")
|
||||
Mes("沿这条路走,只会离 沙漠风暴矿洞 越来越远。")
|
||||
ResetCamera()
|
||||
Mes("先往回走,再朝谷地南侧找矿道。看到旧木梁和矿车轨迹,就说明方向对了。")
|
||||
|
||||
func OnTulimshar():
|
||||
LookAtNpc("To Tulimshar")
|
||||
Mes("沿那条路往北,能回到 图利姆沙 的城墙下。")
|
||||
ResetCamera()
|
||||
Mes("只要沙尘没有太厚,城墙从这里几乎就能看见。看到旗帜,就继续朝旗帜走。")
|
||||
@@ -0,0 +1,33 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.DESERT_DEEP_XAKELBAEL
|
||||
|
||||
#
|
||||
func OnAreaEnter(player : PlayerAgent):
|
||||
var inst : WorldInstance = WorldAgent.GetInstanceFromAgent(npc)
|
||||
if not inst or inst.id != player.get_rid().get_id():
|
||||
return
|
||||
|
||||
var questState : int = player.progress.GetQuest(QUEST_ID)
|
||||
if questState != ProgressCommons.DESERT_DEEP_XAKELBAEL.DEFEATED:
|
||||
SpawnXakelbael(inst)
|
||||
|
||||
npc.RemoveTrigger()
|
||||
|
||||
func SpawnXakelbael(inst : WorldInstance):
|
||||
var spawn : SpawnObject = SpawnObject.new()
|
||||
spawn.map = inst.map
|
||||
spawn.type = "Npc"
|
||||
spawn.nick = "Xakelbael"
|
||||
spawn.id = spawn.nick.hash()
|
||||
spawn.spawn_position = Vector2i(1331, 1478)
|
||||
spawn.spawn_offset = Vector2i(5, 5)
|
||||
spawn.direction = ActorCommons.Direction.UP
|
||||
spawn.state = ActorCommons.State.IDLE
|
||||
spawn.trigger_radius = 120.0
|
||||
spawn.own_script = "tonori/sandstorm/XakelbaelGlobal.gd"
|
||||
spawn.player_script = "tonori/sandstorm/Xakelbael.gd"
|
||||
spawn.is_persistant = false
|
||||
spawn.respawn_delay = 0.0
|
||||
WorldAgent.CreateAgent(spawn, inst.id)
|
||||
@@ -0,0 +1,16 @@
|
||||
extends NpcScript
|
||||
|
||||
# Quest ID
|
||||
const questID : int = ProgressCommons.Quest.SANDSTORM_MINE_ABANDONED_TREASURE
|
||||
|
||||
# Reward items
|
||||
var chestMineKeyID : int = DB.GetCellHash("Chest Mine Key")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(questID):
|
||||
ProgressCommons.SANDSTORM_MINE_ABANDONED_TREASURE.INACTIVE:
|
||||
if HasSpace(1):
|
||||
Mes("碎石下面露出一把生锈钥匙,柄上还刻着旧矿工的编号。")
|
||||
SetQuest(questID, ProgressCommons.SANDSTORM_MINE_ABANDONED_TREASURE.KEY_FOUND)
|
||||
AddItem(chestMineKeyID, 1)
|
||||
@@ -0,0 +1,95 @@
|
||||
extends NpcScript
|
||||
|
||||
const QUEST_ID = ProgressCommons.Quest.SANDSTORM_NATHAN_WATER
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("你好,我是看守内森。平时我在港口站岗,今天被派来守这个快把人烤熟的矿洞入口。")
|
||||
Mes("如果我说话有点乱,那是太阳先动的手。")
|
||||
|
||||
var questState : ProgressCommons.SANDSTORM_NATHAN_WATER = GetQuest(QUEST_ID) as ProgressCommons.SANDSTORM_NATHAN_WATER
|
||||
Choice("这里就是沙漠风暴矿洞入口?", OnEntrance)
|
||||
match questState:
|
||||
ProgressCommons.SANDSTORM_NATHAN_WATER.STARTED:
|
||||
Choice("关于那瓶水。", OnWaitingWater)
|
||||
ProgressCommons.SANDSTORM_NATHAN_WATER.REWARDS_WITHDREW:
|
||||
Choice("现在感觉好点了吗?", OnComplete)
|
||||
Choice("我先去别处看看。", Farewell)
|
||||
|
||||
func Farewell():
|
||||
Chat("小心脚下,沙子会把旧轨道盖得像没存在过一样。")
|
||||
|
||||
# Default dialogue flow
|
||||
func OnEntrance():
|
||||
Mes("没错。旧矿道就在这口井旁边,风从里面吹出来时会带着铁锈味。")
|
||||
Mes("以前矿工每天从这里进出。后来沙暴越来越重,沙蝎和别的东西也把下层当成了巢。")
|
||||
Mes("艾基努的人已经进去了,他们要确认矿道能不能重新开放。说实话,我更希望答案是不能。")
|
||||
|
||||
Choice("我就是来加入侦察的。", OnJoinThem)
|
||||
|
||||
func OnJoinThem():
|
||||
Mes("真的?你看起来不像矿工。没有镐,也没有一脸认命的表情。")
|
||||
|
||||
Choice("我不是来采矿的,只负责侦察。", OnJustScouting)
|
||||
|
||||
func OnJustScouting():
|
||||
Mes("明白了。那就进去吧,里面的人应该正等你。")
|
||||
Mes("先别急着深入。入口层确认安全后,再考虑往废弃矿层和更深处走。")
|
||||
Mes("如果你听见像石头在呼吸的声音,别逞强,先退回来。")
|
||||
|
||||
Choice("谢谢,内森。", OnNiceDay)
|
||||
if GetQuest(QUEST_ID) == ProgressCommons.SANDSTORM_NATHAN_WATER.INACTIVE:
|
||||
Choice("有什么能帮你的吗?", OnJobEasier)
|
||||
|
||||
func OnNiceDay():
|
||||
Chat("等我能回港口看海,那才叫好日子。")
|
||||
|
||||
# Water quest
|
||||
func OnJobEasier():
|
||||
Mes("既然你问了,我确实想要一瓶水。")
|
||||
Mes("不是喝的,我还有一点能喝的。")
|
||||
Mes("我只是想把水倒在脸上,让自己别像挂在太阳底下的肉干。")
|
||||
Mes("这请求听起来很蠢,但在这里站半天后,你会理解的。")
|
||||
|
||||
Choice("我理解,我会帮你找一瓶。", AcceptQuest)
|
||||
Choice("抱歉,我现在有更紧急的事。", RefuseQuest)
|
||||
|
||||
func RefuseQuest():
|
||||
Mes("没事,我懂。忘了我提过这事吧。")
|
||||
Mes("大概就是因为我太会抱怨,才被派到这里来。")
|
||||
Action(Farewell)
|
||||
|
||||
func AcceptQuest():
|
||||
Mes("我就知道你会懂。水是生命,浇脸上的水也是。")
|
||||
Narrate("内森低头看了看脚边被风埋住一半的靴子。")
|
||||
Mes("我会在这里等你。反正我想走也走不了。")
|
||||
SetQuest(QUEST_ID, ProgressCommons.SANDSTORM_NATHAN_WATER.STARTED)
|
||||
if HasItem(DB.GetCellHash("Water Bottle")):
|
||||
Choice("我身上正好有一瓶。", OnDeliverWater)
|
||||
Choice("我去找找。", Farewell)
|
||||
|
||||
func OnWaitingWater():
|
||||
Mes("是你啊。抱歉,风沙一大,我看谁都像会走路的土堆。")
|
||||
Mes("找到水瓶了吗?")
|
||||
if HasItem(DB.GetCellHash("Water Bottle")):
|
||||
Choice("找到了。", OnDeliverWater)
|
||||
Choice("还没有,我继续找。", Farewell)
|
||||
|
||||
func OnDeliverWater():
|
||||
var waterBottleHash : int = DB.GetCellHash("Water Bottle")
|
||||
if HasItem(waterBottleHash):
|
||||
RemoveItem(waterBottleHash)
|
||||
SetQuest(QUEST_ID, ProgressCommons.SANDSTORM_NATHAN_WATER.REWARDS_WITHDREW)
|
||||
Mes("谢谢你,朋友。终于能喘口气了。")
|
||||
Narrate("内森把你带来的水迅速倒在脸上和脖子上。")
|
||||
Narrate("水顺着盔甲缝隙流进沙地,很快就被热风带走。")
|
||||
AddExp(50)
|
||||
AddGP(100)
|
||||
Action(OnComplete)
|
||||
else:
|
||||
Action(Farewell)
|
||||
|
||||
func OnComplete():
|
||||
Mes("这正是我需要的。你不知道这有多救命。")
|
||||
Mes("现在我只需要再来一瓶。")
|
||||
Chat("开玩笑的。大部分是。")
|
||||
@@ -0,0 +1,32 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("等等,旅人。风向几分钟就变一次,别急着把自己交给沙子。")
|
||||
Mes("如果你要去矿洞,让旧井一直在左手边。还有,别追沙尘里那些会动的影子。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnMainChoice():
|
||||
Choice("矿洞附近发生了什么?", OnMines)
|
||||
Choice("你见过异常的宠物吗?", OnPets)
|
||||
Choice("出发前有什么建议?", OnAdvice)
|
||||
Choice("我该继续赶路了。", Farewell)
|
||||
|
||||
func OnMines():
|
||||
Mes("女王 想重新开放矿洞,可沙漠已经有好几年时间把那里变成自己的巢。")
|
||||
Mes("沙蝎藏在暖石缝里,蛇会贴着薄沙游动,更深处还有一些不像普通动物的东西。")
|
||||
Mes("艾基努的侦察队先进去,是因为总得有人在矿工送命前搞清楚里面到底有多糟。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnPets():
|
||||
Mes("见过不少。风平时啾啾鸟会沿路盘旋,沙虫聚在仙人掌根旁,入夜后矿洞入口基本归沙蝎。")
|
||||
Mes("想捕捉的话,先削弱它,再准备备用捕捉护符。沙漠不会等你慢慢翻包。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnAdvice():
|
||||
Mes("水、护目镜、一只你信得过的宠物。顺序别弄错。")
|
||||
Mes("如果风变红,找岩石躲。如果沙声突然安静,说明附近有东西在听。")
|
||||
OnMainChoice()
|
||||
|
||||
func Farewell():
|
||||
Chat("狂风压下来时,把身子放低。")
|
||||
@@ -0,0 +1,48 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("沿这条路往东走,就会离开 图利姆沙谷地,进入 玛纳伊尔海岸 的方向。")
|
||||
Mes("你是在找路,还是在确认自己没有被风带偏?")
|
||||
DisplayChoices()
|
||||
|
||||
func DisplayChoices(hideChoice : int = -1):
|
||||
if hideChoice != 1:
|
||||
Choice("我在找 沙漠风暴矿洞。", OnMines)
|
||||
if hideChoice != 2:
|
||||
Choice("这片谷地有什么要注意?", OnValley)
|
||||
if hideChoice != 3:
|
||||
Choice("玛纳伊尔海岸是什么地方?", OnManayir)
|
||||
if hideChoice != 4:
|
||||
Choice("谢谢,我知道了。", Farewell)
|
||||
|
||||
func OnMines():
|
||||
LookAtNpc("To Mines")
|
||||
Mes("从这里直接往南,就能到 沙漠风暴矿洞。")
|
||||
ResetCamera()
|
||||
Mes("矿洞荒废很久了,不过我刚才看见一队 图利姆沙 人往那边去。")
|
||||
Mes("他们不像普通商队,更像是带着目的来的。你如果也要下矿,最好先确认补给和宠物状态。")
|
||||
DisplayChoices()
|
||||
|
||||
func OnValley():
|
||||
Mes("图利姆沙谷地 是 托诺里 沙漠里少见的低谷,城就靠这里躲开最狠的热风。")
|
||||
Mes("城墙把谷地、港口和居民区圈在一起,也把大部分野兽和沙暴挡在外面。")
|
||||
Mes("但相对安全不等于安全。南边旧住区有失控的 卡奥雷,西边石台地更容易迷路。")
|
||||
DisplayChoices()
|
||||
|
||||
func OnManayir():
|
||||
Mes("那里靠海,是 托诺里 少数气候温和的地方。风里有盐味,沙子也不像谷地里这么烫。")
|
||||
Mes("海滩外伸出一片半岛,我们称它为 纳瓦。")
|
||||
Mes("玛纳伊尔教团 就在那里研究 玛纳、星象和一些普通人听完会头痛的东西。")
|
||||
|
||||
Choice("玛纳伊尔教团是什么?", OnManayirOrder)
|
||||
DisplayChoices(3)
|
||||
|
||||
func OnManayirOrder():
|
||||
Mes("那是一支古老的法师组织,研究 玛纳 的方式比商人算账还认真。")
|
||||
Mes("旧故事里说,他们曾在远古时代治理过 图利姆沙。现在他们更愿意待在塔里,偶尔才和城里交易。")
|
||||
Mes("我的族人尊 玛纳 为 圣灵。我们和 玛纳伊尔 交换知识,也互相保持距离。智慧有时比刀更锋利。")
|
||||
DisplayChoices()
|
||||
|
||||
func Farewell():
|
||||
Chat("顺着路标走,别让风替你决定方向。")
|
||||
@@ -0,0 +1,21 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.DESERT_DEEP_XAKELBAEL)
|
||||
if questState == ProgressCommons.DESERT_DEEP_XAKELBAEL.DEFEATED:
|
||||
Mes("你比我记住的更强。")
|
||||
Mes("但深层矿道不会因为一次胜利就恢复安静。")
|
||||
Mes("我们还会再见。卡奥雷 从不只留下一个影子。")
|
||||
else:
|
||||
Mes("谁踏进了这截被遗忘的根脉?")
|
||||
Mes("矿工带走铁,王冠带走命令,而你带着宠物和一身不知天高地厚的勇气。")
|
||||
Mes("这里的 玛纳树 早已听不见祈祷,只剩 卡奥雷 在石头里回响。")
|
||||
Mes("如果你要替图利姆沙打开这条路,就先证明你能活着穿过我的影子。")
|
||||
Action(npc.ownScript.StartFight)
|
||||
|
||||
func OnQuit():
|
||||
super.OnQuit()
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.DESERT_DEEP_XAKELBAEL)
|
||||
if questState == ProgressCommons.DESERT_DEEP_XAKELBAEL.DEFEATED:
|
||||
npc.ownScript.RunAway.call_deferred()
|
||||
@@ -0,0 +1,84 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.DESERT_DEEP_XAKELBAEL
|
||||
|
||||
const exitDelay : float = 8.0
|
||||
const exitPosition : Vector2 = Vector2(1760, 2533)
|
||||
|
||||
#
|
||||
var player : PlayerAgent = null
|
||||
var playerModifier : StatModifier = null
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Callback.PlugCallback(npc.ready, DisableAIBehaviour)
|
||||
|
||||
func DisableAIBehaviour():
|
||||
npc.aiBehaviour = AICommons.Behaviour.NONE
|
||||
AI.Stop(npc)
|
||||
|
||||
func OnAreaEnter(_player : PlayerAgent):
|
||||
if IsVisible() and _player and not _player.ownScript:
|
||||
var questState : int = _player.progress.GetQuest(QUEST_ID)
|
||||
if questState != ProgressCommons.DESERT_DEEP_XAKELBAEL.DEFEATED:
|
||||
player = _player
|
||||
Callback.OneShotCallback(player.tree_exiting, OnPlayerLeft)
|
||||
npc.Interact(player)
|
||||
|
||||
func OnPlayerLeft():
|
||||
RemovePlayerModifier()
|
||||
if player:
|
||||
NpcCommons.SetQuest(player, QUEST_ID, ProgressCommons.DESERT_DEEP_XAKELBAEL.INACTIVE)
|
||||
player = null
|
||||
|
||||
# Player modifier
|
||||
func AddPlayerModifier():
|
||||
if not playerModifier and player:
|
||||
playerModifier = AddModifier(CellCommons.Modifier.DodgeRate, 10000, player)
|
||||
|
||||
func RemovePlayerModifier():
|
||||
if playerModifier and player:
|
||||
RemoveModifier(playerModifier, player)
|
||||
playerModifier = null
|
||||
|
||||
# Actions
|
||||
func StartFight():
|
||||
NpcCommons.SetQuest(player, QUEST_ID, ProgressCommons.DESERT_DEEP_XAKELBAEL.FIGHTING)
|
||||
|
||||
SetVisible(false)
|
||||
AddPlayerModifier()
|
||||
|
||||
var mobs : Array[MonsterAgent] = Spawn(npc.data._id, 1, npc.position, Vector2i.DOWN)
|
||||
if not mobs.is_empty():
|
||||
var monsterAgent : MonsterAgent = mobs[0]
|
||||
monsterAgent.agent_killed.connect(OnMonsterKilled)
|
||||
AI.Refresh(monsterAgent)
|
||||
|
||||
func OnMonsterKilled(mob : BaseAgent):
|
||||
RemovePlayerModifier()
|
||||
|
||||
npc.position = mob.position
|
||||
RemoveAgent(mob)
|
||||
SetState(ActorCommons.State.DEATH)
|
||||
SetVisible(true)
|
||||
|
||||
NpcCommons.SetQuest(player, QUEST_ID, ProgressCommons.DESERT_DEEP_XAKELBAEL.DEFEATED)
|
||||
|
||||
if player and ActorCommons.IsAlive(player) and not player.ownScript:
|
||||
player.AddScript(npc)
|
||||
if player.ownScript:
|
||||
player.ownScript.ApplyStep()
|
||||
|
||||
func RunAway():
|
||||
if player:
|
||||
Callback.ClearOneShot(player.tree_exiting)
|
||||
player = null
|
||||
|
||||
SetState(ActorCommons.State.IDLE)
|
||||
|
||||
AddModifier(CellCommons.Modifier.WalkSpeed, 200)
|
||||
|
||||
AI.Reset(npc)
|
||||
npc.WalkToward(exitPosition)
|
||||
AddTimer(npc, exitDelay, WorldAgent.RemoveAgent.bind(npc))
|
||||
@@ -0,0 +1,37 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("被派到内墙值守,算是守卫里难得的轻松差事。")
|
||||
Mes("外墙那边要盯野兽和沙暴,我这里主要负责把好奇的人拦在宫门外。")
|
||||
Mes("红女王 正在照料她的花园。除非你真有要紧事,否则别打扰她。")
|
||||
OnMainChoice()
|
||||
|
||||
# Main choice loop
|
||||
func OnMainChoice():
|
||||
Choice("这座大建筑是什么?", OnCastle)
|
||||
Choice("西边通向哪里?", OnWest)
|
||||
Choice("南边是什么地方?", OnSouth)
|
||||
Choice("我先走了。", Farewell)
|
||||
|
||||
# Answers
|
||||
func OnCastle():
|
||||
Mes("那是 红女王 的城堡,也是 图利姆沙 的中枢。")
|
||||
Mes("如果你有真正重要的消息,可以申请觐见;如果只是想看热闹,我建议你转身去市场。")
|
||||
Mes("城堡里还有大陆第二大的藏书馆,书量几乎能追上 玛纳伊尔 塔。法师们听到这句通常会假装没听见。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnWest():
|
||||
Mes("西边是 祖尼石台地 和更荒的石台地。路不直,风也不讲道理。")
|
||||
Mes("那一带有蛇、盗贼留下的旧营地,也有比我们更懂沙漠的部族。别把陌生土地当成空地图。")
|
||||
Mes("真要过去,就贴着路标走,水袋装满,别随便碰看起来像祭坛或陷阱的东西。两者通常都不欢迎客人。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnSouth():
|
||||
Mes("南边能看到旧仙人掌田和废弃住区。那里以前有人住,现在只剩风声和倒下的围栏。")
|
||||
Mes("沙暴一年比一年近,最后把大家逼回城墙后面。")
|
||||
Mes("卡奥雷 最近又不安分,守卫队不想再失去一片街区。你如果去南边,至少带一只可靠的宠物。")
|
||||
OnMainChoice()
|
||||
|
||||
func Farewell():
|
||||
Chat("别在宫门前逗留太久。")
|
||||
@@ -0,0 +1,25 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match randi_range(0, 5):
|
||||
0: SeenClay()
|
||||
1: GoingToSea()
|
||||
2: Circles()
|
||||
3: Chat("那块石头像不像一只睡着的小宠物?我觉得很像。")
|
||||
4: Chat("小心躲起来的海盗!他们最喜欢抢没有写名字的藏宝图。")
|
||||
5: Chat("别擦掉地上的粉笔线,我还没画完港口呢!")
|
||||
|
||||
func SeenClay():
|
||||
Mes("你看到我的粉笔了吗?")
|
||||
Mes("我猜是守卫拿走了。他们站岗太无聊,肯定想偷偷画自己的城堡。")
|
||||
|
||||
func GoingToSea():
|
||||
Mes("总有一天我要坐船出海,去看看 图利姆沙 以外的世界。")
|
||||
Mes("我听说北边有一座城市,沙子又白又冷,踩上去会像面粉一样响。")
|
||||
|
||||
func Circles():
|
||||
Mes("你会画很圆很圆的圆吗?我会!爸爸教我的。")
|
||||
Mes("薇画不圆,她画出来的圆像吃饱了的方块。")
|
||||
Mes("她不喜欢我笑,所以玩井字棋时总要执叉号。")
|
||||
Mes("我现在叫她狂野的叉。她说这个名字听起来像冒险队队长。")
|
||||
@@ -0,0 +1,7 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(ProgressCommons.Quest.GRAIN_IN_THE_SAND):
|
||||
ProgressCommons.GRAIN_IN_THE_SAND.STARTED:
|
||||
Chat("一个封好的货桶。蜡封颜色不对,不是里斯基姆要找的那批。")
|
||||
@@ -0,0 +1,50 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.TULIMSHAR_OLD_FRIENDSHIP
|
||||
var sealedLettersID : int = DB.GetCellHash("Sealed Letters")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(QUEST_ID)
|
||||
match questState:
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.ENVELOPES_FOUND:
|
||||
ReceiveLetters()
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.LETTERS_DELIVERED, \
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.REWARDS_WITHDREW:
|
||||
FreeRoaming()
|
||||
_:
|
||||
TulimsharWestWallLightTrigerGlobal.CallGuard(own)
|
||||
|
||||
func ReceiveLetters():
|
||||
if HasItem(sealedLettersID):
|
||||
Mes("你是谁?")
|
||||
Choice("弗罗斯特让我来的。他让我把这些给你。", GiveLetters)
|
||||
else:
|
||||
Mes("你看起来有话要说。可你手里什么都没有。")
|
||||
Mes("有东西要给我时再回来。我还有墙要巡。")
|
||||
|
||||
func GiveLetters():
|
||||
Mes("什么。他让你带这些来?")
|
||||
Narrate("议员博恩斯翻看那些信,手指在封口处停了很久。")
|
||||
Mes("我认得这笔迹。")
|
||||
Mes("很旧了。那时 女王 还把我们分派在不同岗位,我们甚至还没守同一段墙。")
|
||||
Mes("弗罗斯特处理人。我处理石头。分工就是这样。")
|
||||
Mes("有一阵子,这办法很好。")
|
||||
Mes("后来 女王 不断加压。更多命令,更多临时要求,而且永远不能只把事情做好。")
|
||||
Mes("弗罗斯特开始给一切立规程。我说,我们已经够难了,不需要再多一层压力。")
|
||||
Mes("他说我把他关在外面,总是不告诉任何人就做决定。")
|
||||
Mes("也许他说得对。语言不是我的工具,从来不是。")
|
||||
Mes("我只想把东西建好,然后让别人停止争论我为什么这么建。")
|
||||
Mes("最后我叫他走。他走了。故事到此为止。")
|
||||
Mes("...")
|
||||
Mes("显然并没有。否则我不会还在这里,守着一段没人真的想攻破的墙。")
|
||||
Mes("除了你。不过既然弗罗斯特让你来,那另当别论。")
|
||||
RemoveItem(sealedLettersID)
|
||||
SetQuest(QUEST_ID, ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.LETTERS_DELIVERED)
|
||||
Mes("把这个信封带回去给他。他会知道里面是什么。")
|
||||
Mes("再告诉他,城墙还在。就这句。他会明白。")
|
||||
|
||||
func FreeRoaming():
|
||||
Mes("又是你。走廊现在对你开放,我说话算数。")
|
||||
Mes("我旁边的图书架后有条通道,可以通到城墙外。知道的人不多,别让它变成市场传闻。")
|
||||
@@ -0,0 +1,137 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.TUTORIAL)
|
||||
if questState < ProgressCommons.TUTORIAL.ELANORE_DONE:
|
||||
OnSendToKaelForRecovery()
|
||||
elif questState < ProgressCommons.TUTORIAL.KAEL_DONE:
|
||||
OnSendToKael()
|
||||
elif questState < ProgressCommons.TUTORIAL.EKINU_DONE:
|
||||
OnKaelReport()
|
||||
else:
|
||||
OnComplete()
|
||||
|
||||
#
|
||||
func OnSendToKaelForRecovery():
|
||||
Mes("你已经醒了?")
|
||||
LookAtNpc("Kael")
|
||||
Mes("先去找凯尔。他负责确认你能不能上路,也会给你说明为什么必须选择一只初始宠物。")
|
||||
ResetCamera()
|
||||
|
||||
func OnSendToKael():
|
||||
Mes("你看见那些沙虫了吗?")
|
||||
Mes("恶心,但不能忽视。听老人说,它们以前没这么大,也没这么多。")
|
||||
Mes("仙人掌农户受影响最大。沙虫啃坏作物,仙人掌怪又被 卡奥雷 侵蚀,再拖下去城里的药材和食物都会出问题。")
|
||||
LookAtNpc("Kael")
|
||||
Mes("看守凯尔在东边的仙人掌田附近。")
|
||||
ResetCamera()
|
||||
Mes("如果你想证明自己不是巡逻队捡回来的麻烦,就去帮他清理田地。")
|
||||
|
||||
# Kael's report
|
||||
func OnKaelReport():
|
||||
Mes("凯尔那边处理完了?")
|
||||
Choice("处理完了。凯尔说我能帮你们的远征。", OnExpedition)
|
||||
|
||||
func OnExpedition():
|
||||
Mes("嗯,他判断得没错。")
|
||||
Mes("我们确实还缺一个能应付突发战斗的人。城墙不能抽走太多守卫,你这种外来帮手反而合适。")
|
||||
Mes("你要往南走,去沙漠风暴矿洞。名字不是吓唬人的,那片谷地风向混乱,沙会把路和怪物一起藏起来。")
|
||||
Choice("为什么要去那里?", OnWhyExpedition)
|
||||
Choice("我具体要做什么?", OnJobExplanation)
|
||||
|
||||
func OnWhyExpedition():
|
||||
Mes("那片矿洞以前盛产铁矿,整片区域又算红女王的私产,所以王宫一直惦记着它。")
|
||||
Mes("后来沙暴加重,矿工不是被风吞掉,就是被矿道里的怪物袭击,矿洞才被迫废弃。")
|
||||
Mes("现在王宫缺钱,女王又下令不惜代价重开矿洞。")
|
||||
Mes("她当然不会亲自去确认下面有什么危险,受苦的永远是被派去干活的人。")
|
||||
Choice("我具体要做什么?", OnJobExplanation)
|
||||
|
||||
func OnJobExplanation():
|
||||
Mes("你的任务是侦察矿洞路线,确认旧矿道里有没有足以杀死矿工的大威胁。")
|
||||
Mes("能避开的就记录,必须清理的就处理。别把每场战斗都当成证明自己的机会。")
|
||||
|
||||
if GetQuest(ProgressCommons.Quest.TUTORIAL) < ProgressCommons.TUTORIAL.EKINU_DONE:
|
||||
var shortSwordID : int = DB.GetCellHash("Short Sword")
|
||||
var desertGogglesID : int = DB.GetCellHash("Desert Goggles")
|
||||
Mes("出城前不能让你空手去。")
|
||||
Mes("拿着短剑和沙漠护目镜。风沙会抢走视线,怪物会抢走犹豫的时间。")
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.EKINU_DONE)
|
||||
AddItem(shortSwordID)
|
||||
AddItem(desertGogglesID)
|
||||
AddExp(50)
|
||||
|
||||
Mes("这些足够让你自保,但不保证你能赢下所有战斗。")
|
||||
Mes("遇到危险就跑。死在沙地里没有荣耀,只会让别人多挖一个坑。")
|
||||
|
||||
TeachSkill(DB.GetCellHash("Run"))
|
||||
DisplayActions(["gp_run"])
|
||||
Narrate("按住奔跑键可以冲刺,用来赶路或脱离危险。")
|
||||
Narrate("冲刺会消耗耐力,别在真正需要逃命前把耐力耗空。")
|
||||
|
||||
Mes("差不多准备好了。")
|
||||
LookAtNpc("Gilgames")
|
||||
Mes("不过出城前先找吉尔伽美什说几句。他守着城门,见过太多新人把简单错误变成遗言。")
|
||||
ResetCamera()
|
||||
|
||||
Mes("其他守卫已经先出发了。到城外找看守道森,他会告诉你矿洞入口怎么走。")
|
||||
if GetQuest(ProgressCommons.Quest.MINE_EXPLORATION) < ProgressCommons.MINE_EXPLORATION.STARTED:
|
||||
SetQuest(ProgressCommons.Quest.MINE_EXPLORATION, ProgressCommons.MINE_EXPLORATION.STARTED)
|
||||
|
||||
OnMainChoice()
|
||||
|
||||
# Main choice loop
|
||||
func OnMainChoice():
|
||||
if GetQuest(ProgressCommons.Quest.MINE_EXPLORATION) == ProgressCommons.MINE_EXPLORATION.STARTED:
|
||||
Choice("再说一遍我的任务。", OnJobExplanation)
|
||||
Choice("红女王是什么样的人?", OnRedQueen)
|
||||
Choice("遇到危险怎么办?", OnStrangerDanger)
|
||||
Choice("明白了,我出发。", Farewell)
|
||||
|
||||
# Attack and flee
|
||||
func OnStrangerDanger():
|
||||
Mes("能先手就先手,不能赢就撤。")
|
||||
Mes("你的宠物不是用来替你送死的,受伤太重就换路线、补给、或者直接回城。")
|
||||
DisplayActions(["gp_target"])
|
||||
DisplayActions(["gp_interact"])
|
||||
DisplayActions(["gp_run"])
|
||||
Narrate("按住奔跑键可以冲刺,也可以在危险时拉开距离。")
|
||||
Narrate("冲刺会消耗耐力,需要时再用。")
|
||||
OnMainChoice()
|
||||
|
||||
# 红女王 chain
|
||||
func OnRedQueen():
|
||||
Mes("红女王,正式点叫卡罗琳娜一世,是这座城名义上的统治者。")
|
||||
Mes("她还自称 托诺里 女王,好像城墙外的沙子也会听她命令。")
|
||||
Mes("她说自己继承了古代 白金王朝 的血统。实际情况是,她父亲原本只是个非常聪明的仙人掌农户。")
|
||||
Choice("听起来你很讨厌她。", OnDislikeQueen)
|
||||
Choice("她父亲是农户?", OnRedQueenFather)
|
||||
|
||||
func OnRedQueenFather():
|
||||
Mes("是。他让临终的老国王相信自己是私生子。")
|
||||
Mes("老国王没有别的孩子,又确实喜欢他,就把继承权给了他。公平地说,她父亲很聪明,也比现在的女王更懂治理。")
|
||||
Mes("可他死后,女儿只剩下王冠和故事。没人真心喜欢她,所以她更需要血统传说来撑住面子。")
|
||||
Choice("听起来你很讨厌她。", OnDislikeQueen)
|
||||
|
||||
func OnDislikeQueen():
|
||||
Mes("讨厌这个词太轻了。")
|
||||
Mes("她冷漠、自私,只关心王宫花园和自己的脸面。")
|
||||
Mes("别到处说是我讲的。巡逻队不怕风沙,但没人想因为几句真话被王宫找麻烦。")
|
||||
Mes("她关心那些花,胜过关心被派去矿洞送命的人。")
|
||||
Choice("那我们最好先做正事。", OnMainChoice)
|
||||
|
||||
# Expedition started
|
||||
func Farewell():
|
||||
if randi() % 2:
|
||||
Chat("保持警觉。")
|
||||
else:
|
||||
Chat("完整地回来。")
|
||||
|
||||
func OnComplete():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.MINE_EXPLORATION)
|
||||
if questState == ProgressCommons.MINE_EXPLORATION.STARTED:
|
||||
Mes("准备出发时,去城外找看守道森。")
|
||||
else:
|
||||
Mes("你很幸运,在哥布林发现你之前先被我们捡到。看到你恢复得不错,我也放心些。")
|
||||
|
||||
OnMainChoice()
|
||||
@@ -0,0 +1,164 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.TUTORIAL)
|
||||
match questState:
|
||||
ProgressCommons.TUTORIAL.INACTIVE:
|
||||
OnFirstMeeting()
|
||||
ProgressCommons.TUTORIAL.INTRO_ITEMS_GIVEN:
|
||||
OnSendToKaelForCheck()
|
||||
ProgressCommons.TUTORIAL.POTION_GIVEN:
|
||||
OnSendToKaelForCheck()
|
||||
ProgressCommons.TUTORIAL.CLOTHES_GIVEN:
|
||||
OnSendToKaelForCheck()
|
||||
ProgressCommons.TUTORIAL.UI_EXPLAINED:
|
||||
OnSendToKaelForCheck()
|
||||
_:
|
||||
Mes("你回来了。需要药剂,还是想问些城里的事?")
|
||||
OnMainChoice()
|
||||
|
||||
# First meeting
|
||||
func OnFirstMeeting():
|
||||
var waterBottleID : int = DB.GetCellHash("Water Bottle")
|
||||
var cactusSourCandyID : int = DB.GetCellHash("Cactus Sour Candy")
|
||||
|
||||
Mes("醒了?欢迎来到图利姆沙。")
|
||||
Mes("你差一点就倒在城墙看不见的地方了。巡逻队在沙地边缘发现你时,你已经晒到说不出话。")
|
||||
Mes("我是埃拉诺。先喝点水,再吃这块仙人掌酸糖。别急着站太久,你的身体还没完全缓过来。")
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.INTRO_ITEMS_GIVEN)
|
||||
AddItem(waterBottleID)
|
||||
AddItem(cactusSourCandyID)
|
||||
OnFeelingChoice()
|
||||
|
||||
func OnFeelingChoice():
|
||||
Choice("我好多了,谢谢。", OnFeelingBetter)
|
||||
Choice("还是有点虚弱。", OnFeelingWeak)
|
||||
|
||||
func OnFeelingWeak():
|
||||
var cactusDrinkID : int = DB.GetCellHash("Cactus Drink")
|
||||
|
||||
Mes("那再拿一杯仙人掌饮料。剩下的就只能靠时间了,亲爱的。")
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.POTION_GIVEN)
|
||||
AddItem(cactusDrinkID)
|
||||
OnFeelingBetter()
|
||||
|
||||
func OnFeelingBetter():
|
||||
Mes("能回答问题就好。关于你为什么会独自出现在沙漠里,凯尔会继续问。")
|
||||
Mes("他负责巡逻队的初步确认,也负责给刚恢复的人安排第一只同行宠物。")
|
||||
OnSendToKaelForCheck()
|
||||
|
||||
func OnGiveStarterClothes():
|
||||
var cottonShirtID : int = DB.GetCellHash("Cotton Shirt")
|
||||
var linenShortsID : int = DB.GetCellHash("Shorts")
|
||||
|
||||
Mes("不管你从哪里来,能站起来就是好事。图利姆沙需要愿意帮忙的人。")
|
||||
Mes("最近沙漠越来越不安稳。东边山里有一群迷信 卡奥雷 的狂热者,袭击旅人,甚至曾经差点冲破城墙。")
|
||||
Mes("先把这身破布换掉吧。城里人会看衣服判断你是不是刚从沙地里被捡回来。")
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.CLOTHES_GIVEN)
|
||||
AddItem(cottonShirtID, 1, "Used")
|
||||
AddItem(linenShortsID, 1, "Used")
|
||||
OnExplainUI()
|
||||
|
||||
func OnExplainUI():
|
||||
Mes("放你到城里乱跑之前,我先讲几件保命的事。")
|
||||
HighlightUI(UICommons.UITarget.STATINDICATOR)
|
||||
Narrate("这些是你的关键状态。探索和战斗时要随时留意。")
|
||||
HighlightUI(UICommons.UITarget.HEALTHBAR)
|
||||
Narrate("生命值代表你还能承受多少伤害。")
|
||||
HighlightUI(UICommons.UITarget.MANABAR)
|
||||
Narrate("玛纳 支撑技能释放。玛纳 不足时,许多能力无法使用。")
|
||||
HighlightUI(UICommons.UITarget.STAMINABAR)
|
||||
Narrate("耐力影响奔跑、攻击和体力动作。耗尽后会明显变慢。")
|
||||
HighlightUI(UICommons.UITarget.MENUINDICATOR)
|
||||
Narrate("菜单可以查看背包、技能、任务、设置等信息。")
|
||||
HighlightUI(UICommons.UITarget.ACTION_BAR)
|
||||
Narrate("快捷栏可以放常用技能和物品。战斗时每一秒都很重要。")
|
||||
HighlightUI(UICommons.UITarget.INVENTORY)
|
||||
Narrate("背包窗口可以管理物品、装备、药剂和收集品。")
|
||||
HighlightUI(UICommons.UITarget.NONE)
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.UI_EXPLAINED)
|
||||
Action(OnMainChoice)
|
||||
|
||||
# Main choice loop
|
||||
func HasAllIngredients() -> bool:
|
||||
return HasItem(DB.GetCellHash("Maggot Slime"), 6) and HasItem(DB.GetCellHash("Water Bottle")) and HasItem(DB.GetCellHash("Cactus Drink"))
|
||||
|
||||
func OnMainChoice():
|
||||
var sideQuestState : int = GetQuest(ProgressCommons.Quest.ELANORE_POTION)
|
||||
if sideQuestState == ProgressCommons.ELANORE_POTION.STARTED and HasAllIngredients():
|
||||
Choice("我带来了你要的材料。", OnPotionQuestTurnIn)
|
||||
elif sideQuestState == ProgressCommons.ELANORE_POTION.STARTED:
|
||||
Choice("药剂材料还差什么?", OnPotionQuestReminder)
|
||||
else:
|
||||
Choice("有什么我能帮忙的吗?", OnHelpWithPotions)
|
||||
Choice("卡奥雷 是什么?", OnExplainKaore)
|
||||
Choice("你是谁?", OnExplainSelf)
|
||||
if GetQuest(ProgressCommons.Quest.TUTORIAL) >= ProgressCommons.TUTORIAL.ELANORE_DONE:
|
||||
Choice("谢谢,我先走了。", Farewell)
|
||||
|
||||
# Help with potions
|
||||
func OnHelpWithPotions():
|
||||
Mes("当然。我经常给守卫和居民调制治疗药剂,伤口、脱水和轻度 卡奥雷 侵蚀都能先稳住。")
|
||||
Mes("药剂需要材料。你刚恢复,先做点不太危险的收集工作,也能熟悉城外生态。")
|
||||
Mes("我需要 6 份沙虫黏液、1 瓶水和 1 杯仙人掌饮料。带回来后,我会给你一瓶仙人掌药剂。")
|
||||
SetQuest(ProgressCommons.Quest.ELANORE_POTION, ProgressCommons.ELANORE_POTION.STARTED)
|
||||
if GetQuest(ProgressCommons.Quest.TUTORIAL) < ProgressCommons.TUTORIAL.ELANORE_DONE:
|
||||
OnSendToKael()
|
||||
else:
|
||||
OnMainChoice()
|
||||
|
||||
func OnPotionQuestReminder():
|
||||
Mes("还需要 6 份沙虫黏液、1 瓶水和 1 杯仙人掌饮料。收齐后再来找我。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnPotionQuestTurnIn():
|
||||
Mes("谢谢你。这些材料够我马上调一批新的治疗药剂。")
|
||||
Mes("在城门边帮人,比困在高塔或王宫里讨论规矩有用得多。图利姆沙的领导者真该多看看这里。")
|
||||
RemoveItem(DB.GetCellHash("Maggot Slime"), 6)
|
||||
RemoveItem(DB.GetCellHash("Water Bottle"))
|
||||
RemoveItem(DB.GetCellHash("Cactus Drink"))
|
||||
SetQuest(ProgressCommons.Quest.ELANORE_POTION, ProgressCommons.ELANORE_POTION.INACTIVE)
|
||||
AddItem(DB.GetCellHash("Cactus Potion"))
|
||||
OnMainChoice()
|
||||
|
||||
# What is 卡奥雷
|
||||
func OnExplainKaore():
|
||||
Mes("玛纳 是连接生命的能量。卡奥雷 则像腐败的 玛纳,它不滋养生命,只会扭曲、侵蚀,让生物变得狂躁甚至半死不活。")
|
||||
LookAtNpc("Nina")
|
||||
Mes("如果你想知道更多,去问我的学徒 妮娜。她守着城里的 灵魂石碑,对 玛纳 和 卡奥雷 的解释比我更系统。")
|
||||
ResetCamera()
|
||||
OnMainChoice()
|
||||
|
||||
# Who are you
|
||||
func OnExplainSelf():
|
||||
Mes("我是埃拉诺,图利姆沙和周边土地的 卡维。外人通常把我们称作德鲁伊。")
|
||||
Mes("我所属的 卡乌马图阿 传承守护着很古老的知识。不过现在你不用背这些名词。先活下来,再慢慢了解这个世界。")
|
||||
OnMainChoice()
|
||||
|
||||
func Farewell():
|
||||
if randi() % 2:
|
||||
Chat("出城前检查水和药。")
|
||||
else:
|
||||
Chat("别一个人硬闯沙暴。")
|
||||
|
||||
# Tutorial conclusion
|
||||
func OnSendToKael():
|
||||
Mes("我不能把你留在这里一整天。你需要在城里站稳脚跟。")
|
||||
Mes("看守凯尔正负责城墙内侧的巡逻和仙人掌田。如果你想找点正经事做,先去见他。")
|
||||
LookAtNpc("Kael")
|
||||
Mes("他就在东北边,靠近几棵棕榈树。")
|
||||
Mes("沿着这面墙走到拐角,再往上走就能看见他。")
|
||||
ResetCamera()
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.ELANORE_DONE)
|
||||
DisplayActions(["gp_interact", "gp_target"])
|
||||
Narrate("靠近 角色 后使用互动键可以交谈,也可以先用目标键选中对象。")
|
||||
|
||||
func OnSendToKaelForCheck():
|
||||
Mes("先去找凯尔。")
|
||||
Mes("你的身体能不能撑住外面的风、你醒来前发生了什么、还有初始宠物的选择,都由他来说明。")
|
||||
LookAtNpc("Kael")
|
||||
Mes("他就在东北边,靠近几棵棕榈树。沿着这面墙走到拐角,再往上走就能看见他。")
|
||||
ResetCamera()
|
||||
DisplayActions(["gp_interact", "gp_target"])
|
||||
Narrate("靠近凯尔后使用互动键交谈。")
|
||||
@@ -0,0 +1,7 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnAreaEnter(player : PlayerAgent):
|
||||
if player and not player.ownScript:
|
||||
if player.progress.GetQuest(ProgressCommons.Quest.TUTORIAL) == ProgressCommons.TUTORIAL.INACTIVE:
|
||||
own.Interact(player)
|
||||
@@ -0,0 +1,12 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
match GetQuest(ProgressCommons.Quest.GRAIN_IN_THE_SAND):
|
||||
ProgressCommons.GRAIN_IN_THE_SAND.STARTED:
|
||||
OnSearch()
|
||||
|
||||
func OnSearch():
|
||||
SetQuest(ProgressCommons.Quest.GRAIN_IN_THE_SAND, ProgressCommons.GRAIN_IN_THE_SAND.SEARCHED_CRATES)
|
||||
Mes("深蓝色蜡封上压着 阿尔蒂斯 的纹章。就是这一桶。")
|
||||
Mes("里面是几袋磨得很细的面粉,和里斯基姆描述的一样。")
|
||||
@@ -0,0 +1,107 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.TULIMSHAR_OLD_FRIENDSHIP
|
||||
var sealedLettersID : int = DB.GetCellHash("Sealed Letters")
|
||||
var heavyEnvelopeID : int = DB.GetCellHash("Heavy Envelope")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(QUEST_ID)
|
||||
match questState:
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.INACTIVE:
|
||||
QuestInactive()
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.STARTED:
|
||||
QuestStarted()
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.ENVELOPES_FOUND:
|
||||
QuestEnvelopesFound()
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.LETTERS_DELIVERED:
|
||||
QuestRewards()
|
||||
ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.REWARDS_WITHDREW:
|
||||
QuestCompleted()
|
||||
|
||||
func QuestInactive():
|
||||
Mes("小心脚下,新的仙人掌刚冒头,刺比看起来更快。")
|
||||
Mes("抱歉,我不太习惯有人来这张长椅边聊天。离开宫里以后,访客就少多了。")
|
||||
Mes("我以前是宫廷顾问。几年前辞了职,那地方每个人肩上都压着太多东西。")
|
||||
Mes("现在这里只有我、土和仙人掌。至少种出来的东西能帮城里人熬过旱季。")
|
||||
Mes("你有没有反复想过同一个决定?如果当时换一种说法、晚一点开口,事情会不会完全不同?")
|
||||
Choice("你在想什么?", Lore)
|
||||
Choice("我该走了。", Dismiss)
|
||||
|
||||
func QuestStarted():
|
||||
Mes("还在找吗?西墙走廊不欢迎没有许可的人。")
|
||||
Choice("再说说博恩斯。", Lore)
|
||||
Choice("信在哪里?", Directions)
|
||||
Choice("我会处理。", Dismiss)
|
||||
|
||||
func QuestEnvelopesFound():
|
||||
Mes("你找到了。好,好。")
|
||||
Mes("把封好的信交给议员博恩斯。我刚才看见你离开后,他立刻进了走廊。")
|
||||
Mes("他的直觉一直很准。也可能是你太努力不被发现,反而弄出了动静。总之,他会在那里面。")
|
||||
|
||||
func QuestRewards():
|
||||
if HasItem(heavyEnvelopeID):
|
||||
Mes("你回来了。他说了什么。")
|
||||
Mes("这个信封,很重。")
|
||||
Mes("...")
|
||||
Mes("金币。他把金币放在这里,还写了我的名字。")
|
||||
Mes("女王 第一次把我们派到同一段城墙时,我们各自留了一份钱给对方。万一哪天事情糟到必须离开,至少还有路费。")
|
||||
Mes("我以为我走之后,他早就把这份用掉了。如果他真用了,我也不会怪他。")
|
||||
Mes("我配不上这封信。它该给一个比我更懂得做朋友的人。")
|
||||
Mes("拿着吧。你一个下午做成的事,比我们这些年做得都多。")
|
||||
RemoveItem(heavyEnvelopeID)
|
||||
AddGP(1000)
|
||||
SetQuest(QUEST_ID, ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.REWARDS_WITHDREW)
|
||||
else:
|
||||
Mes("你找到博恩斯了吗?他在西墙走廊里。")
|
||||
|
||||
func QuestCompleted():
|
||||
Mes("今年的仙人掌长势不错。看起来,只要根还在,很多东西都能重新开始。")
|
||||
Mes("我一直在想,我应该去那条走廊。不是今天,但我已经决定会去。")
|
||||
Mes("他一直留着那些信。这说明有些门并没有真的关死,对吧?")
|
||||
|
||||
func Lore():
|
||||
Mes("我曾经有个同僚,议员博恩斯。很聪明的人,什么都能修,什么都能造。")
|
||||
Mes("只是他话少。比起解释一堵墙为什么该重修,他宁愿直接把墙拆了再砌好。")
|
||||
Mes("而我负责和人打交道:排班、调解争执、让每个人知道下一步该做什么。")
|
||||
Mes("我们一起撑住这些城墙很多年。在 女王 手下,这不算小事。")
|
||||
Choice("后来发生了什么?", Conflict)
|
||||
Choice("我该走了。", Dismiss)
|
||||
|
||||
func Conflict():
|
||||
Mes("女王 的命令越来越多,而且永远要按她的方式做。")
|
||||
Mes("我开始制定规程。什么事都写流程,什么错误都加一条规则。我以为只要把一切整理清楚,压力就不会压垮大家。")
|
||||
Mes("博恩斯不这么看。他说我只是把更多压力堆到已经快撑不住的人身上。")
|
||||
Mes("可他也会直接动手、直接决定,不告诉我,也不告诉别人。我总是在事后才知道。")
|
||||
Mes("我们都想守住同一段墙。只是走着走着,我们不再讨论怎么守,而是在争谁的办法才算正确。")
|
||||
Mes("现在回头看,我犯过太多错,没资格说自己全对。但那时候,我们谁也不肯退一步。")
|
||||
Mes("最后他让我离开。我真的离开了。我不为这件事骄傲,只是当时觉得自己碍了所有人的路。")
|
||||
Mes("那已经是很多年前了,可我还是常常想起。")
|
||||
if GetQuest(QUEST_ID) == ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.INACTIVE:
|
||||
Choice("我能帮上什么吗?", Quest)
|
||||
Choice("听起来很遗憾。", Dismiss)
|
||||
|
||||
func Quest():
|
||||
Mes("其实,也许有。")
|
||||
Mes("就在我们左边的西墙走廊尽头,穿过议员博恩斯的巡逻区,有个小房间,里面有一排书架。")
|
||||
Mes("书架上有一个信封。那是我们当年被 女王 分派到不同岗位时写给彼此的信,在一切变坏之前。")
|
||||
Mes("我不知道它能不能改变什么。但也许他重新读到那些字,会想起我们并不总是这样。")
|
||||
Mes("走廊有守卫巡逻。贴着阴影走,别站进亮处。被发现的话,守卫会把你带出去。")
|
||||
Choice("我去取。", Accept)
|
||||
Choice("现在不行。", Decline)
|
||||
|
||||
func Directions():
|
||||
Mes("就在左边西墙走廊的尽头,图书架上方。")
|
||||
Mes("记住,别进亮处。守卫接到的是严格命令:没有许可的人一律带离。")
|
||||
|
||||
func Accept():
|
||||
SetQuest(QUEST_ID, ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.STARTED)
|
||||
Mes("谢谢你,真的。")
|
||||
Directions()
|
||||
|
||||
func Decline():
|
||||
Chat("我明白。这对陌生人来说,确实要求太多了。")
|
||||
|
||||
func Dismiss():
|
||||
Chat("好吧。仙人掌不会自己照顾自己。")
|
||||
@@ -0,0 +1,58 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.TUTORIAL)
|
||||
if questState >= ProgressCommons.TUTORIAL.EKINU_DONE:
|
||||
Mes("你就是艾基努临时收下的新人?很好,至少你还知道先问守门人。")
|
||||
Mes("出城之后,沙子不会听你解释,怪物也不会等你准备好。想问什么,现在问。")
|
||||
OnTutorialResume()
|
||||
else:
|
||||
Mes("离城门远点。还没得到巡逻队许可的人,不要堵在这里。")
|
||||
|
||||
# Common questions
|
||||
func OnTutorialResume():
|
||||
Choice("我该怎么变强?", OnStat)
|
||||
Choice("如果迷路了怎么办?", OnMinimap)
|
||||
Choice("背包和快捷栏怎么用?", OnShortcut)
|
||||
Choice("城外最该小心什么?", OnWarning)
|
||||
Choice("没问题了。", Farewell)
|
||||
|
||||
func Farewell():
|
||||
Chat("活着回来。别让我多写一份报告。")
|
||||
|
||||
# Explanations
|
||||
func OnStat():
|
||||
Mes("完成委托、战斗、探索和帮助别人都会让你成长。别只盯着一条路,托诺里 的麻烦从来不排队。")
|
||||
HighlightUI(UICommons.UITarget.STAT)
|
||||
Narrate("升级后可以获得属性点。按照你的战斗方式分配,再确认选择。")
|
||||
Narrate("力量提高物理伤害、移动速度和负重。")
|
||||
Narrate("敏捷影响攻击节奏、攻击距离和闪避能力。")
|
||||
Narrate("体质提高生命值、恢复能力和整体防御。")
|
||||
Narrate("耐力让你跑得更久、恢复更快,也更容易连续行动。")
|
||||
Narrate("专注影响 玛纳,并让技能更稳定地发挥效果。")
|
||||
HighlightUI(UICommons.UITarget.STATINDICATOR)
|
||||
Narrate("出城前看一眼生命、玛纳 和耐力。带着空条冲进荒野,不叫勇敢,叫给巡逻队添工作。")
|
||||
HighlightUI(UICommons.UITarget.NONE)
|
||||
Mes("你会需要每一点优势。沙漠里的敌人不一定强,但它们很擅长等你犯错。")
|
||||
OnTutorialResume()
|
||||
|
||||
func OnMinimap():
|
||||
Mes("地图是你的第二双眼睛。看不清路时先看地图,别硬凭记忆穿沙暴。")
|
||||
HighlightUI(UICommons.UITarget.MINIMAP)
|
||||
Narrate("迷路时可以在地图上确认目标位置,再朝目标移动。")
|
||||
HighlightUI(UICommons.UITarget.NONE)
|
||||
OnTutorialResume()
|
||||
|
||||
func OnShortcut():
|
||||
Mes("常用的药、捕捉道具和技能都放到顺手的位置。等沙蝎扑到脸上再翻包,就太晚了。")
|
||||
HighlightUI(UICommons.UITarget.ACTION_BAR)
|
||||
Narrate("可以把常用物品、技能或动作放进快捷栏,战斗和探索时更快使用。")
|
||||
HighlightUI(UICommons.UITarget.NONE)
|
||||
OnTutorialResume()
|
||||
|
||||
func OnWarning():
|
||||
Mes("第一,小心风。风沙会遮住路,也会遮住正在靠近你的东西。")
|
||||
Mes("第二,别把宠物当成工具。它们会救你的命,但前提是你也照顾它们。")
|
||||
Mes("第三,别相信王宫说的每一句话。巡逻队守的是城,不是红女王的面子。")
|
||||
OnTutorialResume()
|
||||
@@ -0,0 +1,232 @@
|
||||
extends NpcScript
|
||||
|
||||
# Behaviour
|
||||
const ThresholdHandValue : int = 17
|
||||
|
||||
# Card utilities
|
||||
static var RANKS : PackedStringArray = ["王牌", "2", "3", "4", "5", "6", "7", "8", "9", "10", "侍从", "王后", "国王"]
|
||||
static var SUITS : PackedStringArray = [
|
||||
"黑桃",
|
||||
"红心",
|
||||
"方片",
|
||||
"梅花"
|
||||
]
|
||||
|
||||
# Game state
|
||||
var deck : Array = []
|
||||
var playerHand : Array = []
|
||||
var dealerHand : Array = []
|
||||
|
||||
# Helper
|
||||
static func _CardName(card : int) -> String:
|
||||
return "%s%s" % [SUITS[floori(card / 13.0)], RANKS[card % 13]]
|
||||
|
||||
static func _CardValue(card : int) -> int:
|
||||
var rank : int = card % 13
|
||||
if rank == 0: return 11
|
||||
if rank >= 10: return 10
|
||||
return rank + 1
|
||||
|
||||
static func _HandValue(hand : Array) -> int:
|
||||
var value : int = 0
|
||||
var aces : int = 0
|
||||
for card : int in hand:
|
||||
value += _CardValue(card)
|
||||
if card % 13 == 0:
|
||||
aces += 1
|
||||
while value > 21 and aces > 0:
|
||||
value -= 10
|
||||
aces -= 1
|
||||
return value
|
||||
|
||||
static func _HandStr(hand : Array) -> String:
|
||||
var parts : PackedStringArray = []
|
||||
for card : int in hand:
|
||||
parts.append(_CardName(card))
|
||||
return ", ".join(parts) + " (%d)" % _HandValue(hand)
|
||||
|
||||
static func _NewDeck() -> Array:
|
||||
var d : Array = []
|
||||
d.resize(52)
|
||||
for i : int in range(52):
|
||||
d[i] = i
|
||||
d.shuffle()
|
||||
return d
|
||||
|
||||
# General flow
|
||||
func OnStart():
|
||||
Mes("欢迎,欢迎!你是来找人,还是来找一局好牌?")
|
||||
Mes("听过 21 点 吗?别被名字吓到,规矩简单,胆量和分寸才是关键。")
|
||||
Mes("坐下吧。图利姆沙 的风会吹乱很多东西,但吹不乱一副洗好的牌。")
|
||||
DisplayChoices()
|
||||
|
||||
func DisplayChoices():
|
||||
Choice("挑战 海兰德", StartDealer)
|
||||
Choice("帮我找个对手", StartPvP)
|
||||
Choice("讲讲规则", ShowRules)
|
||||
Choice("今天先不玩", Decline)
|
||||
|
||||
func ShowRules():
|
||||
Mes("规则很简单:尽量接近 21 点,但不能超过。")
|
||||
Mes("数字牌按牌面算,花牌都算 10。王牌可以算 1,也可以算 11,看哪种对你更有利。")
|
||||
Mes("比我点数高且不爆牌,你就赢。超过 21,就是爆牌。")
|
||||
Mes("这游戏最难的不是加法,是知道什么时候该停手。许多商人一辈子都没学会。")
|
||||
DisplayChoices()
|
||||
|
||||
func Decline():
|
||||
Chat("想玩牌的时候来找我。好牌不会等人太久。")
|
||||
|
||||
func OnQuit():
|
||||
if npc and npc.ownScript:
|
||||
npc.ownScript.call("LeavePvP", own)
|
||||
super.OnQuit()
|
||||
|
||||
# Player vs Dealer Mode
|
||||
func StartDealer():
|
||||
deck = _NewDeck()
|
||||
playerHand = [deck.pop_back(), deck.pop_back()]
|
||||
dealerHand = [deck.pop_back(), deck.pop_back()]
|
||||
_DealerTurn()
|
||||
|
||||
func _DealerTurn():
|
||||
if _HandValue(playerHand) == 21:
|
||||
_DealerReveal()
|
||||
else:
|
||||
Mes("你的手牌:%s" % _HandStr(playerHand))
|
||||
Mes("我明面上的牌:%s。" % _CardName(dealerHand[0]))
|
||||
Choice("要牌", _DealerHit)
|
||||
Choice("停牌", _DealerReveal)
|
||||
|
||||
func _DealerHit():
|
||||
playerHand.append(deck.pop_back())
|
||||
var value : int = _HandValue(playerHand)
|
||||
if value > 21:
|
||||
Mes("你的手牌:%s" % _HandStr(playerHand))
|
||||
Mes("哎呀,爆牌了!贪心常常只差一张牌,我见过太多次。")
|
||||
Choice("再来一局", StartDealer)
|
||||
Choice("离开", Decline)
|
||||
elif value == 21:
|
||||
_DealerReveal()
|
||||
else:
|
||||
_DealerTurn()
|
||||
|
||||
func _DealerReveal():
|
||||
while _HandValue(dealerHand) < ThresholdHandValue:
|
||||
dealerHand.append(deck.pop_back())
|
||||
var pv : int = _HandValue(playerHand)
|
||||
var dv : int = _HandValue(dealerHand)
|
||||
Mes("你的手牌:%s" % _HandStr(playerHand))
|
||||
Mes("我的手牌:%s" % _HandStr(dealerHand))
|
||||
if dv > 21:
|
||||
Mes("哈!老手也有伸手太长的时候。你赢得漂亮。")
|
||||
elif pv > dv:
|
||||
Mes("嗯,不错。你知道什么时候该停。")
|
||||
elif dv > pv:
|
||||
Mes("经验又赢了一次。别难过,多数人第一次都输给我。")
|
||||
else:
|
||||
Mes("%d 点平局!胆子不错,我承认这一点。" % pv)
|
||||
Choice("再来一局", StartDealer)
|
||||
Choice("离开", Decline)
|
||||
|
||||
# Player vs Player Mode
|
||||
func StartPvP():
|
||||
var result : int = npc.ownScript.call("JoinPvP", own)
|
||||
if result == 0:
|
||||
Mes("好,让我们看看还有谁有胆量坐上这张桌子。稍等。")
|
||||
Choice("查看", _PvPCheck)
|
||||
Choice("取消", _PvPCancel)
|
||||
else:
|
||||
_PvPBegin()
|
||||
|
||||
func _PvPCheck():
|
||||
var game : Dictionary = npc.ownScript.call("GetGame", own)
|
||||
if game.is_empty():
|
||||
Mes("耐心点。好牌手要先学会等待。")
|
||||
Choice("查看", _PvPCheck)
|
||||
Choice("取消", _PvPCancel)
|
||||
elif game.has("result"):
|
||||
_PvPShowResult(game)
|
||||
else:
|
||||
_PvPBegin()
|
||||
|
||||
func _PvPCancel():
|
||||
npc.ownScript.call("LeavePvP", own)
|
||||
Chat("没有牌局?可惜。也许风向一变,你又想玩了。")
|
||||
func _PvPBegin():
|
||||
playerHand = npc.ownScript.call("GetHand", own)
|
||||
Mes("哈!对手来了。让我看看你们谁更懂停手。")
|
||||
_PvPTurn()
|
||||
|
||||
func _PvPTurn():
|
||||
Mes("你的手牌:%s" % _HandStr(playerHand))
|
||||
if _HandValue(playerHand) == 21:
|
||||
Mes("21 点!")
|
||||
_PvPStand()
|
||||
else:
|
||||
Choice("要牌", _PvPHit)
|
||||
Choice("停牌", _PvPStand)
|
||||
|
||||
func _PvPHit():
|
||||
var card : int = npc.ownScript.call("DrawCard", own)
|
||||
if card < 0:
|
||||
_PvPStand()
|
||||
return
|
||||
playerHand.append(card)
|
||||
var value : int = _HandValue(playerHand)
|
||||
if value > 21:
|
||||
Mes("你的手牌:%s" % _HandStr(playerHand))
|
||||
Mes("爆牌!刚才心里那点犹豫,其实已经给过你提醒了。")
|
||||
npc.ownScript.call("FinishHand", own, value, true)
|
||||
_PvPWait()
|
||||
elif value == 21:
|
||||
Mes("你的手牌:%s" % _HandStr(playerHand))
|
||||
_PvPStand()
|
||||
else:
|
||||
_PvPTurn()
|
||||
|
||||
func _PvPStand():
|
||||
npc.ownScript.call("FinishHand", own, _HandValue(playerHand), false)
|
||||
_PvPWait()
|
||||
|
||||
func _PvPWait():
|
||||
var game : Dictionary = npc.ownScript.call("GetGame", own)
|
||||
if game.has("result"):
|
||||
_PvPShowResult(game)
|
||||
else:
|
||||
Mes("你这边结束了。现在等对手做决定。")
|
||||
Choice("查看", _PvPWaitCheck)
|
||||
Choice("认输", _PvPForfeit)
|
||||
|
||||
func _PvPWaitCheck():
|
||||
var game : Dictionary = npc.ownScript.call("GetGame", own)
|
||||
if game.has("result"):
|
||||
_PvPShowResult(game)
|
||||
else:
|
||||
Mes("还在思考。谨慎的人值得尊重,除非他只是忘了轮到自己。")
|
||||
Choice("查看", _PvPWaitCheck)
|
||||
Choice("认输", _PvPForfeit)
|
||||
|
||||
func _PvPShowResult(game : Dictionary):
|
||||
var isP1 : bool = game.get("p1") == own
|
||||
var myVal : int = game.get("p1Value") if isP1 else game.get("p2Value")
|
||||
var oppBust : bool = game.get("p2Busted") if isP1 else game.get("p1Busted")
|
||||
var oppHand : Array = game.get("p2Hand") if isP1 else game.get("p1Hand")
|
||||
var myBust : bool = game.get("p1Busted") if isP1 else game.get("p2Busted")
|
||||
Mes("你的点数:%d%s" % [myVal, "(爆牌)" if myBust else ""])
|
||||
Mes("对手手牌:%s%s" % [_HandStr(oppHand), "(爆牌)" if oppBust else ""])
|
||||
var result : String = game.get("result", "")
|
||||
if result == "draw":
|
||||
Mes("平局!势均力敌,这在我的桌上不常见。")
|
||||
elif (result == "p1" and isP1) or (result == "p2" and not isP1):
|
||||
Mes("胜利归你!今天牌也站在你这边。")
|
||||
else:
|
||||
Mes("可惜。牌有自己的脾气,但它总会再绕回来。")
|
||||
npc.ownScript.call("CleanupGame", own)
|
||||
Choice("再来一局", StartPvP)
|
||||
Choice("离开", Decline)
|
||||
|
||||
func _PvPForfeit():
|
||||
npc.ownScript.call("ForfeitPvP", own)
|
||||
Mes("中途离桌?放在我年轻时,这至少要请全桌喝一轮。")
|
||||
Choice("再来一局", StartPvP)
|
||||
Choice("离开", Decline)
|
||||
@@ -0,0 +1,160 @@
|
||||
extends NpcScript
|
||||
|
||||
const PEYOTE_REQUIRED : int = 5
|
||||
const MAGGOT_REQUIRED : int = 5
|
||||
const FIELD_POSITION : Vector2 = Vector2(2912, 1312)
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.TUTORIAL)
|
||||
if questState < ProgressCommons.TUTORIAL.ELANORE_DONE:
|
||||
OnInitialRecovery()
|
||||
elif questState == ProgressCommons.TUTORIAL.ELANORE_DONE:
|
||||
OnFirstMeeting()
|
||||
elif questState == ProgressCommons.TUTORIAL.KAEL_MET:
|
||||
OnCheckProgress()
|
||||
elif questState == ProgressCommons.TUTORIAL.KAEL_DONE:
|
||||
OnSendToEkinu()
|
||||
elif questState == ProgressCommons.TUTORIAL.EKINU_DONE:
|
||||
OnComplete()
|
||||
|
||||
# Opening recovery and starter choice
|
||||
func OnInitialRecovery():
|
||||
var waterBottleID : int = DB.GetCellHash("Water Bottle")
|
||||
var cactusSourCandyID : int = DB.GetCellHash("Cactus Sour Candy")
|
||||
|
||||
Mes("站稳。先让我看一下你的脸色。")
|
||||
Mes("巡逻队在城外沙地边缘发现你时,你已经脱水到说不出话。埃拉诺把你从最危险的状态里拉了回来,现在轮到我确认你还能不能上路。")
|
||||
Mes("抬手,握拳,深呼吸。很好。你还虚,但不是那种一阵风就能吹倒的虚。")
|
||||
Mes("先拿着水和仙人掌酸糖。图利姆沙欢迎活人,不欢迎逞强的人。")
|
||||
AddItem(waterBottleID)
|
||||
AddItem(cactusSourCandyID)
|
||||
OnOpeningBackstory()
|
||||
|
||||
func OnOpeningBackstory():
|
||||
Mes("你是被沙漠送到城门口的陌生人。身上没有能说明身份的东西,脚印却从风暴方向断断续续延过来。")
|
||||
Mes("最近 托诺里 不安稳。卡奥雷 的波动让野外宠物变得暴躁,东边还有一群把 卡奥雷 当信仰的疯子在袭击旅人。")
|
||||
Mes("所以我不会让你空手出城,也不会让你在城里闲逛到下一场麻烦砸过来。")
|
||||
OnStarterPetIntro()
|
||||
|
||||
func OnStarterPetIntro():
|
||||
Mes("先选一只初始宠物。不是装饰,也不是玩伴。它会替你挡住第一口毒牙,陪你学会怎么在这里活下去。")
|
||||
Mes("三只都经过巡逻队训练,性格和战斗方式不一样。")
|
||||
Mes("露莉娅属水,耐久和恢复节奏稳定,适合稳扎稳打。")
|
||||
Mes("啾啾鸟属风,动作快,适合先手和灵活周旋。")
|
||||
Mes("绒绒兽是普通系,脾气稳,招式直接,适合不想把战斗想得太复杂的人。")
|
||||
Mes("想清楚就选。没有绝对正确的答案,只有你愿意一起走下去的伙伴。")
|
||||
|
||||
# Initial encounter
|
||||
func OnFirstMeeting():
|
||||
Mes("选好伙伴了?好。能照顾宠物的人,至少比只会照顾自己的人可靠一点。")
|
||||
Mes("现在说正事。我这边正缺人手。")
|
||||
Mes("沙虫最近把仙人掌田啃得一塌糊涂。它们个头大,嘴却灵活,能绕开刺直接钻进茎里。")
|
||||
Mes("一旦钻进去,整株仙人掌就会从里面被吃空。农户看到那种景象,脸色比沙暴天还难看。")
|
||||
Choice("这些沙虫为什么这么大?", OnKaoreExplanation)
|
||||
Choice("听起来很麻烦。", OnWildFauna)
|
||||
Choice("我可以帮忙清理。", OnWildFauna)
|
||||
|
||||
func OnKaoreExplanation():
|
||||
Mes("据说它们很久以前没这么夸张。可那是 卡奥雷时代 之前的事,已经没人亲眼记得。")
|
||||
Mes("卡奥雷 让很多生物变得异常:有的变大,有的暴躁,有的像死了又没完全死。")
|
||||
Mes("沙虫算是我们每天都能看见的麻烦版本。更糟的东西通常藏在城外。")
|
||||
if GetQuest(ProgressCommons.Quest.TUTORIAL) >= ProgressCommons.TUTORIAL.KAEL_DONE:
|
||||
MainChoices()
|
||||
else:
|
||||
Mes("闲话到此为止。我要你进田里把麻烦清掉。")
|
||||
Choice("好,我开始。", OnFieldCleanUp)
|
||||
Choice("城外到底发生了什么?", OnDesertExplanation)
|
||||
|
||||
func OnWildFauna():
|
||||
Mes("不管原因是什么,它们都得被清理。")
|
||||
Mes("城外的 卡奥雷 波动已经影响到城内田地,沙虫不是唯一的问题。")
|
||||
Mes("有些仙人掌怪也被侵蚀了,会跳来跳去,往旁边作物上甩水,像在故意嘲笑农户。")
|
||||
Choice("我去清理它们。", OnFieldCleanUp)
|
||||
Choice("城外到底发生了什么?", OnDesertExplanation)
|
||||
|
||||
func OnDesertExplanation():
|
||||
Mes("卡奥雷 正在影响各种生物。")
|
||||
Mes("它会把活物扭成更糟的样子:更凶、更饿、更难控制。")
|
||||
Mes("被侵蚀得太深时,它们甚至会像死物一样行动。那不是普通疾病,是一种很难洗掉的诅咒。")
|
||||
if GetQuest(ProgressCommons.Quest.TUTORIAL) >= ProgressCommons.TUTORIAL.KAEL_DONE:
|
||||
MainChoices()
|
||||
else:
|
||||
Mes("西边塔里的 玛纳伊尔 法师已经发出警告:托诺里 多处 卡奥雷 正在异常聚集。")
|
||||
Choice("明白了,先处理田地。", OnFieldCleanUp)
|
||||
Choice("玛纳伊尔 是谁?", OnManayir)
|
||||
|
||||
func OnManayir():
|
||||
Mes("玛纳伊尔 是研究 玛纳 的古老组织,就在城西那座塔里。")
|
||||
Mes("他们会监测 玛纳 和 卡奥雷 的流向,像预报天气一样发布警告。")
|
||||
Mes("二十七年前,也是他们宣布 卡奥雷时代 结束。可结束不代表消失,只是没以前那么压得人喘不过气。")
|
||||
Choice("先处理田地。", OnFieldCleanUp)
|
||||
Choice("卡奥雷时代 是什么?", OnAgeOfKaore)
|
||||
|
||||
func OnAgeOfKaore():
|
||||
Mes("我没亲眼经历过,但父辈都记得。那几百年里,卡奥雷 比 玛纳 更常见,变异生物和不死怪物到处都是。")
|
||||
Mes("我们现在抱怨沙虫和仙人掌怪,其实已经比那时候幸运多了。")
|
||||
Choice("先处理眼前的麻烦。", OnFieldCleanUp)
|
||||
|
||||
# Task assignment
|
||||
func OnFieldCleanUp():
|
||||
OnFightTutorial()
|
||||
Mes("先从北边田里的仙人掌怪开始。")
|
||||
LookAtPosition(FIELD_POSITION)
|
||||
Mes("它们是被 卡奥雷 侵蚀的仙人掌,对人不算致命,但已经没法种植。")
|
||||
Mes("它们会乱跳、甩水、惊扰宠物,还会把旁边作物弄坏。")
|
||||
ResetCamera()
|
||||
Mes("清理 5 只仙人掌怪和 5 只沙虫,今天的田地就能暂时安全。")
|
||||
HighlightUI(UICommons.UITarget.PROGRESS)
|
||||
Narrate("任务进度会记录你正在进行的委托和战斗目标。")
|
||||
HighlightUI(UICommons.UITarget.NONE)
|
||||
Narrate("图鉴和任务界面会帮助你确认已击败或遇见的宠物与怪物。")
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.KAEL_MET)
|
||||
|
||||
# Progress check
|
||||
func OnCheckProgress():
|
||||
var peyoteKills : int = GetBestiary("Peyote".hash())
|
||||
var maggotKills : int = GetBestiary("Maggot".hash())
|
||||
if peyoteKills >= PEYOTE_REQUIRED and maggotKills >= MAGGOT_REQUIRED:
|
||||
OnTaskComplete()
|
||||
elif peyoteKills < PEYOTE_REQUIRED:
|
||||
Mes("还没完成。田里还需要再清理 %d 只仙人掌怪。" % (PEYOTE_REQUIRED - peyoteKills))
|
||||
else:
|
||||
Mes("仙人掌怪处理得不错,但还差 %d 只沙虫。" % (MAGGOT_REQUIRED - maggotKills))
|
||||
|
||||
# Task completion
|
||||
func OnTaskComplete():
|
||||
Mes("干得漂亮。")
|
||||
Mes("你处理得比我预想的快,也比很多正式巡逻员稳。")
|
||||
Mes("去向看守艾基努汇报吧。告诉他,我认可你今天的表现。")
|
||||
Mes("我们很快要组织一支小队去沙漠侦察,你可能正适合帮忙。")
|
||||
SetQuest(ProgressCommons.Quest.TUTORIAL, ProgressCommons.TUTORIAL.KAEL_DONE)
|
||||
AddExp(50)
|
||||
|
||||
#
|
||||
func OnSendToEkinu():
|
||||
Mes("准备好后去找看守艾基努。")
|
||||
Mes("他会告诉你下一步怎么做。")
|
||||
MainChoices()
|
||||
|
||||
#
|
||||
func OnComplete():
|
||||
Mes("很高兴又见到你。你看,沙虫还是不肯给我放假。")
|
||||
MainChoices()
|
||||
|
||||
#
|
||||
func MainChoices():
|
||||
Choice("这些沙虫为什么这么异常?", OnKaoreExplanation)
|
||||
Choice("我该怎么战斗?", OnFightTutorial)
|
||||
Choice("城外到底发生了什么?", OnDesertExplanation)
|
||||
Choice("我先走了。", Farewell)
|
||||
|
||||
func Farewell():
|
||||
Chat("出城后别只看前面,背后也可能有东西靠近。")
|
||||
|
||||
func OnFightTutorial():
|
||||
Mes("这不是让你亲手去砍仙人掌怪。让你的宠物上。")
|
||||
Mes("靠近野外宠物会进入宠物对战。进入战斗后,用战斗指令释放技能,用宠物指令切换队伍成员。")
|
||||
Mes("把对手削弱后,可以用捕捉符尝试收服。别一上来就丢,满体力的野外宠物通常不会乖乖进符。")
|
||||
DisplayActions(["gp_interact", "gp_target"])
|
||||
Narrate("接触野外宠物会进入对战。战斗菜单中可以使用技能、捕捉符、切换宠物或逃跑。")
|
||||
@@ -0,0 +1,21 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.TULIMSHAR_OLD_FRIENDSHIP
|
||||
var sealedLettersID : int = DB.GetCellHash("Sealed Letters")
|
||||
var heavyEnvelopeID : int = DB.GetCellHash("Heavy Envelope")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(QUEST_ID)
|
||||
if questState != ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.STARTED:
|
||||
return
|
||||
|
||||
if HasItemsSpace([[sealedLettersID, 1], [heavyEnvelopeID, 1]]):
|
||||
Mes("你在积灰的书本之间找到了两个旧信封。")
|
||||
Mes("一个封得很仔细,另一个意外地沉。")
|
||||
SetQuest(QUEST_ID, ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.ENVELOPES_FOUND)
|
||||
AddItem(sealedLettersID)
|
||||
AddItem(heavyEnvelopeID)
|
||||
else:
|
||||
Mes("你看见了信封,但背包太满,已经装不下它们。")
|
||||
@@ -0,0 +1,95 @@
|
||||
extends NpcScript
|
||||
class_name TulimsharWestWallLightTrigerGlobal
|
||||
|
||||
#
|
||||
const QUEST_ID : int = ProgressCommons.Quest.TULIMSHAR_OLD_FRIENDSHIP
|
||||
const GUARD_SPEED_BOOST : int = 200
|
||||
const APPROACH_DISTANCE : float = 48.0
|
||||
|
||||
#
|
||||
static var activeCatches : Dictionary[int, NpcAgent] = {}
|
||||
|
||||
#
|
||||
func OnAreaEnter(player : PlayerAgent):
|
||||
CallGuard(player)
|
||||
|
||||
static func CallGuard(player : PlayerAgent):
|
||||
if not ActorCommons.IsAlive(player):
|
||||
return
|
||||
|
||||
var playerRID : int = player.get_rid().get_id()
|
||||
if activeCatches.has(playerRID):
|
||||
return
|
||||
|
||||
var questState : int = player.progress.GetQuest(QUEST_ID)
|
||||
if questState >= ProgressCommons.TULIMSHAR_OLD_FRIENDSHIP.LETTERS_DELIVERED:
|
||||
return
|
||||
|
||||
if player.SetState(ActorCommons.State.TRIGGER):
|
||||
var inst : WorldInstance = WorldAgent.GetInstanceFromAgent(player)
|
||||
if inst:
|
||||
var guard : BaseAgent = SpawnGuard(inst)
|
||||
if guard:
|
||||
activeCatches[playerRID] = guard
|
||||
NpcCommons.PushNotification(player, "被守卫发现了!")
|
||||
Callback.AddCallback(player.tree_exiting, Cleanup, [player, guard, playerRID], ConnectFlags.CONNECT_ONE_SHOT)
|
||||
Callback.OneShotCallback(guard.ready, OnGuardReady.bind(player, guard, playerRID))
|
||||
|
||||
static func SpawnGuard(inst : WorldInstance) -> BaseAgent:
|
||||
var spawn : SpawnObject = SpawnObject.new()
|
||||
spawn.map = inst.map
|
||||
spawn.type = "Npc"
|
||||
spawn.nick = "图利姆沙 Guard" if randi() % 2 == 0 else "图利姆沙 Sbire"
|
||||
spawn.id = spawn.nick.hash()
|
||||
spawn.spawn_position = Vector2i(2688, 1472) # tile (84, 46)
|
||||
spawn.spawn_offset = Vector2i.DOWN
|
||||
spawn.player_script = "tonori/tulimshar/PatrolGuardCaught.gd"
|
||||
return WorldAgent.CreateAgent(spawn, inst.id)
|
||||
|
||||
static func OnGuardReady(player : PlayerAgent, guard : NpcAgent, playerRID : int):
|
||||
if not guard or not ActorCommons.IsAlive(player):
|
||||
Cleanup(player, guard, playerRID)
|
||||
return
|
||||
|
||||
var guardRID : int = guard.get_rid().get_id()
|
||||
Launcher.World.BulkPreload(guard, guardRID, player.peerID)
|
||||
player.CheckVisibility(guard)
|
||||
|
||||
# Wait one full update cycle for the SetData to be called
|
||||
StartGuardNavigation.call_deferred(player, guard, playerRID)
|
||||
|
||||
static func StartGuardNavigation(player : PlayerAgent, guard : NpcAgent, playerRID : int):
|
||||
if not guard or not ActorCommons.IsAlive(player):
|
||||
Cleanup(player, guard, playerRID)
|
||||
return
|
||||
|
||||
NpcCommons.AddModifier(guard, CellCommons.Modifier.WalkSpeed, GUARD_SPEED_BOOST)
|
||||
|
||||
AI.Stop(guard)
|
||||
|
||||
# Check if in correct distance to start the guard interaction
|
||||
if (guard.position - player.position).length() < APPROACH_DISTANCE / 2.0:
|
||||
OnGuardArrived(player, guard, playerRID)
|
||||
# Stop right before the player position but still within the trigger position
|
||||
else:
|
||||
var stopPos : Vector2 = player.position + (guard.position - player.position).normalized() * APPROACH_DISTANCE / 2.0
|
||||
guard.WalkToward(stopPos)
|
||||
Callback.OneShotCallback(guard.agent.navigation_finished, OnGuardArrived.bind(player, guard, playerRID))
|
||||
|
||||
static func OnGuardArrived(player : PlayerAgent, guard : NpcAgent, playerRID : int):
|
||||
if not guard or not ActorCommons.IsAlive(player):
|
||||
Cleanup(player, guard, playerRID)
|
||||
return
|
||||
|
||||
guard.Interact(player)
|
||||
|
||||
static func Cleanup(player : PlayerAgent, guard : NpcAgent, playerRID : int):
|
||||
activeCatches.erase(playerRID)
|
||||
if player and is_instance_valid(player):
|
||||
if player.ownScript:
|
||||
NpcCommons.ToggleContext(player, false)
|
||||
player.ClearScript()
|
||||
if player.state == ActorCommons.State.TRIGGER:
|
||||
player.SetState(ActorCommons.State.TRIGGER)
|
||||
if guard and is_instance_valid(guard):
|
||||
WorldAgent.RemoveAgent.call_deferred(guard)
|
||||
@@ -0,0 +1,48 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
if own.stat and own.stat.level < 5:
|
||||
Mes("新面孔?欢迎来到图利姆沙。")
|
||||
Mes("我是玛茜,平时帮外来者认路,也帮本地人把话说清楚。")
|
||||
Mes("这里风沙大,脾气也容易被吹硬。记住一件事:在城里别随便羞辱别人,我们靠互相照应活下去。")
|
||||
else:
|
||||
Mes("想找路、打听城里的事,或者只是想听几句闲话,都可以问我。")
|
||||
OnMainChoice()
|
||||
|
||||
# Main choice loop
|
||||
func OnMainChoice():
|
||||
Choice("给我讲讲这座城。", OnCityOverview)
|
||||
Choice("住在这里是什么感觉?", OnLiveHere)
|
||||
Choice("最近城里有什么传闻?", OnRumors)
|
||||
Choice("我该去哪里补给?", OnSupplies)
|
||||
Choice("我先走了。", Farewell)
|
||||
|
||||
# Answers
|
||||
func OnCityOverview():
|
||||
Mes("图利姆沙夹在东西两侧的山丘之间,像一只缩在石壳里的沙漠甲虫。")
|
||||
Mes("城墙挡住了南边的沙暴,也挡住了许多被 卡奥雷 逼疯的野兽。")
|
||||
Mes("城门附近是巡逻和救治伤员的地方;中央区有市场、面包铺和小游戏;再往北就是港口,外来的货物大多从那里上岸。")
|
||||
Mes("如果你刚醒来没多久,先熟悉城门、市场和港口这三处就够了。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnLiveHere():
|
||||
Mes("这里的人嘴上总说自己习惯了沙漠,其实谁都知道,一个人是扛不过 托诺里 的。")
|
||||
Mes("水井坏了会有人去修,商船晚到会有人分面包,巡逻队缺人时也总有人硬着头皮顶上。")
|
||||
Mes("当然,王宫里的人不一定这么想。他们更喜欢命令和税单。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnRumors():
|
||||
Mes("最近传得最多的是两件事。第一,红女王又想重开沙漠风暴矿洞。")
|
||||
Mes("第二,城外的宠物和怪物越来越不安分,沙虫啃坏了仙人掌田,沙蝎也开始靠近旧矿道。")
|
||||
Mes("如果你能收服几只可靠的伙伴,巡逻队会更愿意相信你不是来添乱的。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnSupplies():
|
||||
Mes("找吃的去里斯基姆的面包铺,找水先看井和商贩,想买药就去找埃拉诺。")
|
||||
Mes("如果要出城,别只带一只宠物。沙地里最糟糕的不是迷路,是你以为自己还能再撑一场战斗。")
|
||||
OnMainChoice()
|
||||
|
||||
# Farewell
|
||||
func Farewell():
|
||||
Chat("风向变得太快时,就先回城墙边歇一会儿。")
|
||||
@@ -0,0 +1,135 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.NINA_HUNGRY)
|
||||
if questState == ProgressCommons.NINA_HUNGRY.INACTIVE:
|
||||
OnIntro()
|
||||
else:
|
||||
Mes("又见面了。灵魂石碑 今天很安静,这是好事。")
|
||||
OnPlayerChoice()
|
||||
|
||||
# Intro
|
||||
func OnIntro():
|
||||
Mes("你好。是埃拉诺让你来的?欢迎。")
|
||||
Mes("你面前的是图利姆沙古老的 灵魂石碑。我负责守护它,也用它的力量保护城里的人。")
|
||||
Mes("当然,是在王宫允许的范围内。这里很多事都要加上这句话。")
|
||||
OnPlayerChoice()
|
||||
|
||||
func OnPlayerChoice():
|
||||
if GetQuest(ProgressCommons.Quest.NINA_HUNGRY) == ProgressCommons.NINA_HUNGRY.STARTED and HasItem(DB.GetCellHash("Croissant")):
|
||||
Choice("我给你带来了可颂。", OnCroissantTurnIn)
|
||||
else:
|
||||
Choice("有人在阻止你使用 石碑?", OnExplainOpposition)
|
||||
Choice("讲讲 玛纳 和 卡奥雷。", OnExplainMana)
|
||||
Choice("灵魂石碑 是什么?", OnExplainMenhir)
|
||||
Choice("我先走了。", Farewell)
|
||||
|
||||
# Opposition and faith
|
||||
func OnExplainOpposition():
|
||||
Mes("不是直接阻止。卡维,也就是外人口中的德鲁伊,一直被允许留在图利姆沙。没有我们,这座城很难熬过干旱和 卡奥雷 侵袭。")
|
||||
Mes("但王国官方信奉 萨维安教义。他们认为 玛纳 和 卡奥雷 一样危险,都应该尽量远离。")
|
||||
Mes("有趣的是,公开反对 玛纳 的人,家人受伤或田地缺雨时,还是会来找我们。")
|
||||
Mes("我只是希望大家能更诚实地面对古老传统。萨维安 的恐惧已经让世界吃过太多苦,现在还催生了崇拜 卡奥雷 的 瓦鲁尼亚人。")
|
||||
Choice("卡维 怎么看待 玛纳?", OnKahwePosition)
|
||||
Choice("我想问别的事。", OnPlayerChoice)
|
||||
Choice("谢谢你,我先走了。", Farewell)
|
||||
|
||||
func OnKahwePosition():
|
||||
Mes("卡维 传承的是 玛纳 与生命和谐共处的知识。我们想恢复 汉图 被毁后失去的平衡。")
|
||||
Choice("汉图 是什么?", OnExplainHantu)
|
||||
Choice("我想问别的事。", OnPlayerChoice)
|
||||
Choice("谢谢你,我先走了。", Farewell)
|
||||
|
||||
func OnExplainHantu():
|
||||
Mes("汉图 也叫 玛纳树,曾经像世界生命力的心脏,能自然引导 玛纳。")
|
||||
Mes("古代有许多 汉图,它们稳定 玛纳,防止 玛纳 腐败成 卡奥雷。")
|
||||
Mes("后来战争和 萨维安教义 的恐惧摧毁了它们。统治者试图创造一个没有 玛纳 的世界。")
|
||||
Mes("结果你已经看见了:玛纳 没有消失,只是失去平衡,留下了 卡奥雷。")
|
||||
Choice("现在局势怎样?", OnCurrentSituation)
|
||||
Choice("我想问别的事。", OnPlayerChoice)
|
||||
Choice("谢谢你,我先走了。", Farewell)
|
||||
|
||||
func OnCurrentSituation():
|
||||
Mes("看你问谁。红女王会说普通人离魔法越远越好。")
|
||||
Mes("可她自己在王宫里照样使用魔法。她真正的意思是:力量最好只掌握在少数人手里。")
|
||||
Mes("我相信魔法是世界的一部分。水也危险,但没人会因为会溺水就封掉所有水井。")
|
||||
Choice("红女王是什么人?", OnRedQueen)
|
||||
Choice("有什么我能帮忙的吗?", OnAskForHelp)
|
||||
|
||||
func OnRedQueen():
|
||||
Mes("她统治图利姆沙,也自称统治整个 托诺里。可城墙之外,听她命令的人并不多。")
|
||||
Mes("祖尼 部族从未承认这个王国。她越控制不了外面,就越想控制城里的人。")
|
||||
Mes("祖尼 仍保留古老魔法,这让他们很难被征服。红女王不想图利姆沙居民也拥有那种独立性。")
|
||||
Choice("讲讲 祖尼。", OnZuni)
|
||||
Choice("有什么我能帮忙的吗?", OnAskForHelp)
|
||||
|
||||
func OnZuni():
|
||||
Mes("祖尼 在 托诺里 生活了很久,久到他们的故事里还记得这片土地不是沙漠时的样子。")
|
||||
Mes("他们和图利姆沙一直有贸易,也大多友好。前提是我们别把士兵派得太远。")
|
||||
Mes("一旦王国越界,他们就会反击。我尊重这一点:他们知道边界在哪里,也愿意守住家园。")
|
||||
Choice("听起来我该更谨慎些。", OnZuniDismissal)
|
||||
Choice("我想见见他们。", OnZuniMarket)
|
||||
|
||||
func OnZuniDismissal():
|
||||
Mes("谨慎总比傲慢好。")
|
||||
OnZuniMarket()
|
||||
|
||||
func OnZuniMarket():
|
||||
Mes("北边市场里常有 祖尼 商人。只要你尊重他们,买不买东西都能聊上几句。")
|
||||
Choice("有什么我能帮忙的吗?", OnAskForHelp)
|
||||
|
||||
# 玛纳 and 卡奥雷
|
||||
func OnExplainMana():
|
||||
Mes("玛纳 常被称作生命力,是活物之间流动的能量。")
|
||||
Mes("正确引导 玛纳,可以施展魔法、治疗土地、维持生命。")
|
||||
Mes("卡奥雷 则是 玛纳 与源头断裂后腐败留下的东西。它不滋养生命,只会侵蚀、扭曲,让生物变得敌对。")
|
||||
Mes("这座 灵魂石碑 用 泽莱石 制成。泽莱石 能储存和释放 玛纳,所以它才能保护城门附近。")
|
||||
OnPlayerChoice()
|
||||
|
||||
# 灵魂石碑 and 泽莱石
|
||||
func OnExplainMenhir():
|
||||
Mes("灵魂石碑 是用巨大 泽莱石 雕成的古代石碑。卡维 会借它引导并扩散 玛纳。")
|
||||
Mes("它启动时能形成保护性的气场,驱散被 卡奥雷 侵蚀的生物,也能稳定周围土地。")
|
||||
Mes("在 卡维 协助下,它还能治疗重伤者。某些时候,甚至能把濒死者的灵魂拉回安全处。")
|
||||
Choice("泽莱石 是什么?", OnExplainZielite)
|
||||
Choice("我想问别的事。", OnPlayerChoice)
|
||||
Choice("谢谢你,我先走了。", Farewell)
|
||||
|
||||
func OnExplainZielite():
|
||||
Mes("泽莱石 是一种天然亲近 玛纳 的稀有矿物,能吸收、储存并释放 玛纳。")
|
||||
Mes("过去它并不少见,但 萨维安教义 掀起反 玛纳 清洗后,很多矿脉和工艺都被毁了。")
|
||||
Mes("现在 泽莱石 多藏在护符、遗迹和少数仍然站立的 灵魂石碑 里。")
|
||||
OnPlayerChoice()
|
||||
|
||||
# Hungry quest
|
||||
func OnAskForHelp():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.NINA_HUNGRY)
|
||||
if questState == ProgressCommons.NINA_HUNGRY.STARTED:
|
||||
Mes("暂时没有。只是,如果你真的路过面包铺,我还在惦记那份点心。")
|
||||
OnPlayerChoice()
|
||||
elif questState == ProgressCommons.NINA_HUNGRY.REWARDS_WITHDREW:
|
||||
Mes("暂时没有,谢谢你还记得问。那份可颂让我今天好多了。")
|
||||
OnPlayerChoice()
|
||||
else:
|
||||
Mes("暂时没有。")
|
||||
Mes("不过我有点饿。不是要你帮我买吃的!我只是从早上开始就没离开过 石碑。")
|
||||
Choice("我去市场时帮你看看点心。", OnStartHungryQuest)
|
||||
Choice("那你记得休息。", Farewell)
|
||||
|
||||
func OnStartHungryQuest():
|
||||
Mes("你真好。我平时不会开口,但现在如果有一份可颂,确实会像小小的奇迹。")
|
||||
Mes("市场的面包铺通常能买到。我要是离开太久,石碑 这边没人照看。")
|
||||
SetQuest(ProgressCommons.Quest.NINA_HUNGRY, ProgressCommons.NINA_HUNGRY.STARTED)
|
||||
|
||||
func OnCroissantTurnIn():
|
||||
Mes("天啊。")
|
||||
Mes("真的是可颂!我没想到你会记得。")
|
||||
RemoveItem(DB.GetCellHash("Croissant"))
|
||||
SetQuest(ProgressCommons.Quest.NINA_HUNGRY, ProgressCommons.NINA_HUNGRY.REWARDS_WITHDREW)
|
||||
AddItem(DB.GetCellHash("Cactus Potion"), 10)
|
||||
AddGP(100)
|
||||
Mes("请收下这些仙人掌药剂,还有一点钱,至少补上你花掉的费用。")
|
||||
|
||||
func Farewell():
|
||||
Chat("愿 灵魂石碑 保佑你一路平安。")
|
||||
@@ -0,0 +1,18 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
const ENTRANCE_POS : Vector2 = Vector2(1536, 1600) # tile (48, 50)
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("站住。")
|
||||
Mes("议员博恩斯的命令:没有许可,任何人不得进入这些走廊。")
|
||||
Mes("我不管你为什么来。转身,出去。")
|
||||
Action(Escort)
|
||||
|
||||
func Escort():
|
||||
if own.state == ActorCommons.State.TRIGGER:
|
||||
own.SetState(ActorCommons.State.TRIGGER)
|
||||
|
||||
var entranceMapID : int = "图利姆沙 Center".hash()
|
||||
Action(NpcCommons.Warp.bind(own, entranceMapID, ENTRANCE_POS))
|
||||
@@ -0,0 +1,111 @@
|
||||
extends NpcScript
|
||||
|
||||
# Reward items
|
||||
var croissantID : int = DB.GetCellHash("Croissant")
|
||||
var cactusSourCandyID : int = DB.GetCellHash("Cactus Sour Candy")
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var questState : int = GetQuest(ProgressCommons.Quest.GRAIN_IN_THE_SAND)
|
||||
match questState:
|
||||
ProgressCommons.GRAIN_IN_THE_SAND.INACTIVE:
|
||||
OnInactive()
|
||||
ProgressCommons.GRAIN_IN_THE_SAND.SEARCHED_CRATES:
|
||||
OnReward()
|
||||
ProgressCommons.GRAIN_IN_THE_SAND.REWARDS_WITHDREW:
|
||||
OnComplete()
|
||||
_:
|
||||
OnKeepLooking()
|
||||
|
||||
# Quest states
|
||||
func OnInactive():
|
||||
Mes("欢迎,旅人。你来得正巧,也来得不太巧:架子上的面包刚刚卖空。")
|
||||
Mes("图利姆沙 没有像样的农田,城外除了沙、风和仙人掌,几乎什么都长不稳。")
|
||||
Mes("我的面粉都从 阿尔蒂斯 坐船运来。靠它做出的 沙暴面包,已经养活这座城很多年了。")
|
||||
Mes("今天清晨有一批货到了码头,可这天气来回跑一趟,回来就没力气揉面了。")
|
||||
Mes("阿尔蒂斯 面包坊的货桶上有深蓝色蜡封。你能去码头帮我把里面的面粉袋带回来吗?")
|
||||
|
||||
QuestChoice()
|
||||
|
||||
func QuestChoice(previousChoice : int = -1):
|
||||
Choice("我去码头看看。", OnAccept)
|
||||
if previousChoice != 1:
|
||||
Choice("沙暴面包 是什么?", OnAskBread)
|
||||
if previousChoice != 2:
|
||||
Choice("沙漠里真的种不出粮食吗?", OnAskDesert)
|
||||
Choice("晚点再说。", OnDecline)
|
||||
|
||||
func OnKeepLooking():
|
||||
Mes("码头那边有线索吗?记住,找带深蓝色蜡封的货桶。")
|
||||
Mes("我会把炉火留着,面粉一到就能开工。")
|
||||
|
||||
func OnComplete():
|
||||
Mes("就算热得像站在炉膛旁边,刚出炉的面包也没人舍得错过。")
|
||||
CompleteChoice()
|
||||
|
||||
func CompleteChoice(previousChoice : int = -1):
|
||||
if previousChoice != 0:
|
||||
Choice("给我讲讲 阿尔蒂斯。", OnAskArtis)
|
||||
if previousChoice != 1:
|
||||
Choice("图利姆沙 靠什么活下来?", OnAskCity)
|
||||
if previousChoice != 2:
|
||||
Choice("沙暴面包 是什么?", OnAskBread)
|
||||
if previousChoice != 3:
|
||||
Choice("沙漠里真的种不出粮食吗?", OnAskDesert)
|
||||
if previousChoice != -1:
|
||||
Choice("你忙吧。", OnFarewell)
|
||||
|
||||
# Optional dialogue
|
||||
func OnAskBread():
|
||||
Mes("我的招牌配方:阿尔蒂斯 的细面粉、仙人掌汁代替清水,再加一撮晒干的沙盐。")
|
||||
Mes("这种面包外壳结实,穿过沙暴也不容易碎,第二天早上还带着香气,所以才叫 沙暴面包。")
|
||||
if IsQuestCompleted(ProgressCommons.Quest.GRAIN_IN_THE_SAND):
|
||||
CompleteChoice(2)
|
||||
else:
|
||||
QuestChoice(1)
|
||||
|
||||
func OnAskDesert():
|
||||
Mes("能长的主要是仙人掌。它们很硬气,我们也很会利用:糖果、饮料、药膏,什么都能做。")
|
||||
Mes("可粮食不一样。托诺里 从来不是产麦子的地方,没有商船,城里的炉火会先灭,人的肚子也会跟着空。")
|
||||
if IsQuestCompleted(ProgressCommons.Quest.GRAIN_IN_THE_SAND):
|
||||
CompleteChoice(3)
|
||||
else:
|
||||
QuestChoice(2)
|
||||
|
||||
func OnAskArtis():
|
||||
Mes("阿尔蒂斯 是海对岸 奥罗拉 海岸上的大港,农田肥沃,工匠也多。")
|
||||
Mes("我妹妹就住在那里。她烤的小饼干特别香,我这里用的面粉也来自她的面包坊。")
|
||||
Mes("图利姆沙 市场上一半的货都靠 阿尔蒂斯 商船补给。少了它们,我们能吃的就只剩仙人掌和耐心了。")
|
||||
CompleteChoice(0)
|
||||
|
||||
func OnAskCity():
|
||||
Mes("贸易。图利姆沙 最擅长的不是种地,而是让来自三片大陆的货物在这里停脚。")
|
||||
Mes("港口、城墙、商队、守卫,还有像我这样盯着下一船面粉的人,拼在一起才撑起这座沙漠城市。")
|
||||
Mes("这也说明了一件事:码头上每一个迟到的货桶,都会让城里某个炉子安静下来。")
|
||||
CompleteChoice(1)
|
||||
|
||||
func OnFarewell():
|
||||
Mes("有空再来。只要炉火还亮,就会有一块新面包等着你。")
|
||||
|
||||
# Transitions to next states
|
||||
func OnAccept():
|
||||
SetQuest(ProgressCommons.Quest.GRAIN_IN_THE_SAND, ProgressCommons.GRAIN_IN_THE_SAND.STARTED)
|
||||
|
||||
Mes("太感谢了,朋友。")
|
||||
Mes("找深蓝色蜡封。看到 阿尔蒂斯 的印记,就说明货没错。")
|
||||
|
||||
func OnDecline():
|
||||
Mes("没关系。炉火会等一会儿,只是别让它等到天黑。")
|
||||
|
||||
func OnReward():
|
||||
Mes("你找到了!太好了。")
|
||||
Mes("有了这些面粉,日落前 图利姆沙 就能闻到 沙暴面包 的香味。")
|
||||
|
||||
SetQuest(ProgressCommons.Quest.GRAIN_IN_THE_SAND, ProgressCommons.GRAIN_IN_THE_SAND.REWARDS_WITHDREW)
|
||||
|
||||
AddItem(cactusSourCandyID, 5)
|
||||
AddItem(croissantID, 5)
|
||||
AddKarma(1)
|
||||
AddExp(20)
|
||||
|
||||
Mes("这些给你:可颂 和 仙人掌酸糖。一个是家传手艺,一个是我在沙暴天里琢磨出来的小发明。")
|
||||
@@ -0,0 +1,41 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
Mes("需要指路?别在这片城墙下乱转,图利姆沙的路看起来直,走起来很会骗人。")
|
||||
OnMainChoice()
|
||||
|
||||
# Main choice loop
|
||||
func OnMainChoice():
|
||||
Choice("港口在哪里?", OnPort)
|
||||
Choice("东边海岸有什么?", OnEast)
|
||||
Choice("沙漠风暴矿洞怎么走?", OnMines)
|
||||
Choice("城里哪里比较安全?", OnSafe)
|
||||
Choice("我先走了。", Farewell)
|
||||
|
||||
# Answers
|
||||
func OnPort():
|
||||
Mes("往北走。你会先闻到海味,再听见水手吵架,那就是港口。")
|
||||
Mes("托诺里 自己产不了多少谷物,外地来的布料、面粉、药材也多靠那里。")
|
||||
Mes("水手工作时别挡路。他们骂人比沙暴还快,而且通常骂得很准。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnEast():
|
||||
Mes("东边是一长段海滩。喜欢沙子的话,那里多到能让你重新讨厌它。")
|
||||
Mes("沿路继续走能靠近 玛纳伊尔 的塔。那些研究 玛纳 的人很少下城,但他们看见的东西比我们多。")
|
||||
Mes("再往东北有座灯塔,天晴时从那里能望见整片海。迷路时认灯塔,比认自己的影子可靠。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnMines():
|
||||
Mes("要去矿洞,就先出城往南,穿过沙漠风暴谷地。")
|
||||
Mes("旧井旁边有入口,内森常被派在那里站岗。如果你看见一个快被晒干的守卫,多半就是他。")
|
||||
Mes("别低估那条路。风会遮住怪物,怪物也会利用风。")
|
||||
OnMainChoice()
|
||||
|
||||
func OnSafe():
|
||||
Mes("城门附近有埃拉诺,灵魂石碑 那边有妮娜,市场人多,通常也安全。")
|
||||
Mes("真正别乱闯的是城堡走廊。巡逻队对陌生人没耐心,尤其是灯光照得到的地方。")
|
||||
OnMainChoice()
|
||||
|
||||
func Farewell():
|
||||
Chat("看路,也看风。风有时候比人诚实。")
|
||||
@@ -0,0 +1,36 @@
|
||||
extends NpcScript
|
||||
class_name SoulMenhirGlobal
|
||||
|
||||
#
|
||||
const REGEN_HEALTH_BONUS : int = 3
|
||||
const REGEN_MANA_BONUS : int = 3
|
||||
const REGEN_STAMINA_BONUS : int = 3
|
||||
|
||||
var playerModifiers : Dictionary[int, Array] = {}
|
||||
|
||||
#
|
||||
func OnAreaEnter(player : PlayerAgent):
|
||||
if not player or not ActorCommons.IsAlive(player):
|
||||
return
|
||||
|
||||
var playerRID : int = player.get_rid().get_id()
|
||||
if playerModifiers.has(playerRID):
|
||||
return
|
||||
|
||||
var mods : Array[StatModifier] = []
|
||||
mods.append(AddModifier(CellCommons.Modifier.RegenHealth, REGEN_HEALTH_BONUS, player))
|
||||
mods.append(AddModifier(CellCommons.Modifier.RegenMana, REGEN_MANA_BONUS, player))
|
||||
mods.append(AddModifier(CellCommons.Modifier.RegenStamina, REGEN_STAMINA_BONUS, player))
|
||||
playerModifiers[playerRID] = mods
|
||||
|
||||
func OnAreaExit(player : PlayerAgent):
|
||||
if not player:
|
||||
return
|
||||
|
||||
var playerRID : int = player.get_rid().get_id()
|
||||
if not playerModifiers.has(playerRID):
|
||||
return
|
||||
|
||||
for mod in playerModifiers[playerRID]:
|
||||
RemoveModifier(mod, player)
|
||||
playerModifiers.erase(playerRID)
|
||||
@@ -0,0 +1,9 @@
|
||||
extends WarpGlobal
|
||||
|
||||
#
|
||||
func OnAreaEnter(player : PlayerAgent):
|
||||
if player and player.progress:
|
||||
if player.progress.GetQuest(ProgressCommons.Quest.TUTORIAL) < ProgressCommons.CompletedProgress:
|
||||
Network.PushNotification("出城前先去找埃拉诺。", player.peerID)
|
||||
return
|
||||
super.OnAreaEnter(player)
|
||||
@@ -0,0 +1,88 @@
|
||||
extends NpcScript
|
||||
|
||||
#
|
||||
func OnStart():
|
||||
var globalScript : TicTacToeGlobal = (npc.ownScript as TicTacToeGlobal)
|
||||
match globalScript.startStep:
|
||||
TicTacToeGlobal.State.NONE:
|
||||
if steps.is_empty():
|
||||
match randi_range(0, 2):
|
||||
0: Mes("要玩井字棋吗?棋盘是我自己画的!")
|
||||
1:
|
||||
Mes("我画不出圆圆的圈,所以我用小方块代替。安迪总笑我,但方块也可以很厉害。")
|
||||
Mes("要玩井字棋吗?")
|
||||
2:
|
||||
Mes("前几天我看到一伙海盗和守卫玩井字棋。守卫输了,但他们说那叫战略撤退。")
|
||||
Mes("你也要玩吗?")
|
||||
else:
|
||||
Mes("要玩井字棋吗?")
|
||||
Choice("和你玩", StartPvE)
|
||||
Choice("找别人玩", StartPvP)
|
||||
Choice("怎么玩?", ShowRules)
|
||||
Choice("晚点再玩", Decline)
|
||||
TicTacToeGlobal.State.X:
|
||||
if globalScript.playerX != own:
|
||||
Mes("嘿,已经有人在等对手了!你可以去挑战他们!")
|
||||
Choice("我来和他们玩!", StartPvP)
|
||||
Choice("怎么玩?", ShowRules)
|
||||
Choice("晚点再玩", Decline)
|
||||
else:
|
||||
Mes("还没人来。你要继续等吗?")
|
||||
Choice("再等一会儿", WaitPvP)
|
||||
Choice("怎么玩?", ShowRules)
|
||||
Choice("我得走了", CancelPvP)
|
||||
TicTacToeGlobal.State.O:
|
||||
var isPlaying : bool = globalScript.playerX == own or globalScript.playerO == own
|
||||
if isPlaying:
|
||||
Mes("嘿,不许偷看提示!快回去下你的棋!")
|
||||
else:
|
||||
Mes("嘘,他们正在下棋!你可以看,但不能乱指。")
|
||||
Choice("好啦好啦", OnQuit)
|
||||
Choice("怎么玩?", ShowRules)
|
||||
if isPlaying:
|
||||
Choice("我得走了", CancelPvP)
|
||||
|
||||
func ShowRules():
|
||||
Mes("你选一个格子,放上自己的记号,然后换另一个人。")
|
||||
Mes("横着、竖着、斜着,只要三个连成一条线就赢。")
|
||||
Mes("如果九个格子都填满还没人连成线,就是平局。平局也不错,只是没有胜利时那么好跳起来。")
|
||||
OnStart()
|
||||
|
||||
func Decline():
|
||||
Chat("好吧,改变主意就来找我,棋盘不会跑掉。")
|
||||
|
||||
# Player vs 角色
|
||||
func StartPvE():
|
||||
var globalScript : TicTacToeGlobal = (npc.ownScript as TicTacToeGlobal)
|
||||
if globalScript.startStep == TicTacToeGlobal.State.NONE and globalScript.StartPvE(own):
|
||||
DisplayActions(["gp_target", "gp_untarget"])
|
||||
Mes("你执叉号!选一个格子,快快快!")
|
||||
else:
|
||||
Mes("等一下,已经有人在玩了!要排队。")
|
||||
|
||||
# Player vs Player
|
||||
func StartPvP():
|
||||
var globalScript : TicTacToeGlobal = (npc.ownScript as TicTacToeGlobal)
|
||||
match globalScript.StartPvP(own):
|
||||
TicTacToeGlobal.State.X:
|
||||
Mes("现在等另一个人来挑战你。")
|
||||
return
|
||||
TicTacToeGlobal.State.O:
|
||||
DisplayActions(["gp_target", "gp_untarget"])
|
||||
Mes("太好了,你们都到齐了!好好玩!")
|
||||
return
|
||||
TicTacToeGlobal.State.NONE:
|
||||
Mes("不行不行,棋盘现在被占用了!")
|
||||
|
||||
func WaitPvP():
|
||||
if (npc.ownScript as TicTacToeGlobal).playerX == own:
|
||||
Chat("一定很快就有人来,大概吧!")
|
||||
|
||||
func CancelPvP():
|
||||
var globalScript : TicTacToeGlobal = (npc.ownScript as TicTacToeGlobal)
|
||||
if globalScript.playerX == own:
|
||||
globalScript.LeaveQueue(own)
|
||||
Chat("啊,这么快就不等了?好吧。")
|
||||
|
||||
func OnQuit():
|
||||
Chat("嘘,别打扰他们下棋。")
|
||||
Reference in New Issue
Block a user