Two gaps between the first quests, both of the same kind: a step the chain assumed rather than asked for. #142 - "collect 5 ore" was followed straight by "build the mothership", which costs twenty. The first thing the chain ever asked for was four times what it had just taught, with nothing in between saying so. A stockpile quest sits between them now. #141 - the crafter quest's brief said "spend ore on the Shipyards doctrine, then put a ship crafter down", which is two unrelated things off one line: open a menu the player has never opened, and place a structure. Researching Shipyards is its own quest now, and it is the one that says where the research tree lives. Every later quest that needs a doctrine still only mentions it in passing - once is enough. That needed a goal kind for researching a doctrine, which the model did not have. Both are pinned as properties rather than as positions in a list. The chain must ask for at least as much ore as the first structure it wants costs; and the first structure that is gated behind a doctrine must have that doctrine as a quest of its own. Only the first - demanding one per building would double the chain for no teaching. One thing that fell out of writing those: the pile is exactly the starting fleet's hold. An interceptor carries 20 and the mothership costs 20, and before the mothership exists there is nowhere to bank anything, so the hold is the only store there is. It fits with no slack at all, so there is now an assertion saying so - a pile larger than the hold would be a quest that cannot be finished, and nothing else would have caught it.
This commit is contained in:
parent
970eafc1de
commit
90c34f6c74
3 changed files with 138 additions and 7 deletions
|
|
@ -26,6 +26,9 @@ extends SceneTree
|
|||
# G. research points only come from conquest, so no quest may ask for a
|
||||
# doctrine that costs them before the conquest quest
|
||||
# H. quests do not run during the prologue
|
||||
# P. #142 - enough rocks are asked for before the first structure is
|
||||
# Q. #141 - the first structure that needs a doctrine has that doctrine as
|
||||
# a quest of its own, so research is taught rather than assumed
|
||||
# I. lines survive having nobody to say them: a quest finished with no
|
||||
# banner alive is read out by the next one that is
|
||||
# J. a planet surface carries the chain too - a quest finished down there
|
||||
|
|
@ -38,6 +41,7 @@ const QUESTS = preload("res://core/Quests.gd")
|
|||
var game_state: Node
|
||||
var stage: int = 0
|
||||
var elapsed: float = 0.0
|
||||
var spoke: bool = false
|
||||
var scene: Node
|
||||
var panel: Control
|
||||
var quest_button: Control
|
||||
|
|
@ -101,6 +105,10 @@ func _catalogue_cases() -> bool:
|
|||
if not (String(goal.resource) in game_state.resource_types()):
|
||||
return _fail("quest %s asks for a resource that does not exist: %s" \
|
||||
% [quest.id, goal.resource])
|
||||
QUESTS.GOAL_RESEARCH:
|
||||
if game_state.skill_node(String(goal.node)).is_empty():
|
||||
return _fail("quest %s asks to research a doctrine that does not exist: %s" \
|
||||
% [quest.id, goal.node])
|
||||
print("catalogue: %d quests, all well formed and none already done" % QUESTS.count())
|
||||
|
||||
# --- F. the hinge ----------------------------------------------------
|
||||
|
|
@ -118,6 +126,70 @@ func _catalogue_cases() -> bool:
|
|||
return _fail("the quest after the mothership is %s, not exploration" % after.id)
|
||||
print("the mothership answers with distance, and exploration follows it")
|
||||
|
||||
# --- P. #142: enough rocks before anything is asked to be built ------
|
||||
# The first structure the chain asks for used to arrive straight after a
|
||||
# five-ore errand, costing four times that, with nothing in between
|
||||
# saying so.
|
||||
var first_build: int = -1
|
||||
for i in range(QUESTS.count()):
|
||||
if String(QUESTS.at(i).goal.kind) == QUESTS.GOAL_BUILDING:
|
||||
first_build = i
|
||||
break
|
||||
if first_build <= 0:
|
||||
return _fail("the chain opens on a build quest, with nothing gathered first")
|
||||
var build_type: String = String(QUESTS.at(first_build).goal.building)
|
||||
var build_price: int = int(game_state.building_costs(build_type).get(GameState.RESOURCE_ORE, 0))
|
||||
var gathered: int = 0
|
||||
for i in range(first_build):
|
||||
var goal_before: Dictionary = QUESTS.at(i).goal
|
||||
if String(goal_before.kind) == QUESTS.GOAL_RESOURCE \
|
||||
and String(goal_before.resource) == GameState.RESOURCE_ORE:
|
||||
gathered = maxi(gathered, int(goal_before.amount))
|
||||
if gathered < build_price:
|
||||
return _fail("the chain asks for a %s costing %d ore, having only ever asked for %d" \
|
||||
% [build_type, build_price, gathered])
|
||||
# ...and the pile has to FIT. Before the first structure exists there is
|
||||
# nowhere to bank anything, so the fleet's own hold is the only store
|
||||
# there is - and a pile larger than it would be a quest that cannot be
|
||||
# finished at all. It currently fits exactly, with no slack, so this is
|
||||
# the assertion that says so out loud rather than leaving it to be
|
||||
# discovered by a player.
|
||||
var starting: PackedStringArray = PackedStringArray()
|
||||
for i in range(GameState.STARTING_SHIP_COUNT):
|
||||
starting.append(GameState.VESSEL_INTERCEPTOR)
|
||||
var hold: int = game_state.fleet_cargo_capacity(starting)
|
||||
if gathered > hold:
|
||||
return _fail("the chain asks for %d ore before anything can bank it, and the starting fleet holds %d" \
|
||||
% [gathered, hold])
|
||||
print("%d ore is asked for before the %s that costs %d, and the opening hold carries %d" \
|
||||
% [gathered, build_type, build_price, hold])
|
||||
|
||||
# --- Q. #141: research is taught before it is assumed ----------------
|
||||
# The first structure in the chain that needs a doctrine must have that
|
||||
# doctrine as a quest of its own first. Only the FIRST one: once the
|
||||
# player has been into the tree, a mention in a brief is enough, and
|
||||
# demanding a research quest per building would double the chain.
|
||||
var taught: Dictionary = {}
|
||||
var checked: bool = false
|
||||
for i in range(QUESTS.count()):
|
||||
var goal_here: Dictionary = QUESTS.at(i).goal
|
||||
if String(goal_here.kind) == QUESTS.GOAL_RESEARCH:
|
||||
taught[String(goal_here.node)] = true
|
||||
continue
|
||||
if checked or String(goal_here.kind) != QUESTS.GOAL_BUILDING:
|
||||
continue
|
||||
var gate: String = String(game_state.research_node_for_building(String(goal_here.building)))
|
||||
if gate == "":
|
||||
continue
|
||||
checked = true
|
||||
if not taught.has(gate):
|
||||
return _fail("the chain asks for a %s, gated behind \"%s\", without ever sending anyone to research it" \
|
||||
% [goal_here.building, gate])
|
||||
print("the first gated structure (%s) has its doctrine \"%s\" as a quest of its own" \
|
||||
% [goal_here.building, gate])
|
||||
if not checked:
|
||||
return _fail("no quest asks for a structure that needs research at all")
|
||||
|
||||
# --- G. nothing asks for points before conquest ----------------------
|
||||
var conquest_at: int = -1
|
||||
for i in range(QUESTS.count()):
|
||||
|
|
@ -261,15 +333,43 @@ func _process(delta: float) -> bool:
|
|||
3:
|
||||
if elapsed < 0.3:
|
||||
return false
|
||||
if String(game_state.active_quest().get("id", "")) != "mothership":
|
||||
return _fail("collecting 5 ore did not finish the ore quest (on %s)" \
|
||||
# #142: five ore finishes the first errand and starts the
|
||||
# stockpile, rather than jumping straight to a structure costing
|
||||
# four times what was just asked for.
|
||||
if String(game_state.active_quest().get("id", "")) != "stockpile":
|
||||
return _fail("collecting 5 ore did not finish the first ore quest (on %s)" \
|
||||
% game_state.active_quest().get("id", "<none>"))
|
||||
if not narration.is_speaking():
|
||||
return _fail("finishing a quest said nothing")
|
||||
print("5 ore collected: the chain moved on to \"%s\"" \
|
||||
% game_state.active_quest().title)
|
||||
print("5 ore done; the chain asks for the pile before the mothership")
|
||||
while narration.dismiss():
|
||||
pass
|
||||
game_state.collect_cargo(15)
|
||||
elapsed = 0.0
|
||||
stage = 31
|
||||
return false
|
||||
31:
|
||||
# A quest completing puts its line up, and the next quest's brief
|
||||
# behind it - and each of those stops the tree (#128), which is
|
||||
# what stops the goal below from ever being checked. Clicked
|
||||
# through the way a player does, rather than waited out.
|
||||
if narration.is_speaking():
|
||||
# Seen here rather than asserted after the fact: by the time
|
||||
# the chain has moved on, the lines it said are gone.
|
||||
spoke = true
|
||||
while narration.dismiss():
|
||||
pass
|
||||
elapsed = 0.0
|
||||
return false
|
||||
if elapsed < 0.3:
|
||||
return false
|
||||
if String(game_state.active_quest().get("id", "")) != "mothership":
|
||||
return _fail("collecting the full 20 ore did not finish the stockpile (on %s, ore=%d, hold cap=%d)" \
|
||||
% [game_state.active_quest().get("id", "<none>"),
|
||||
game_state.available_resource(GameState.RESOURCE_ORE),
|
||||
game_state.fleet_inventory.total_capacity])
|
||||
if not spoke:
|
||||
return _fail("finishing a quest said nothing")
|
||||
print("20 ore collected: the chain moved on to \"%s\"" \
|
||||
% game_state.active_quest().title)
|
||||
|
||||
# --- I. a line said with no banner alive --------------------
|
||||
scene.free()
|
||||
|
|
|
|||
Loading…
Reference in a new issue