Skip to content

Commit

Permalink
Working on new lancedev and enemy conversation plots.
Browse files Browse the repository at this point in the history
  • Loading branch information
jwvhewitt committed Sep 29, 2024
1 parent eea4cbf commit c30a5cb
Show file tree
Hide file tree
Showing 16 changed files with 413 additions and 10 deletions.
18 changes: 18 additions & 0 deletions data/lifepath_earth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"name": "Earth",
"desc": "You are from Earth.",
"stage": "ORIGIN",
"choices": [
{"prompt": "What part of Earth are you from?", "options": [
{
"name": "The Green Zone"
},
{
"name": "The Dead Zone"
}
], "allow_random": true
}
]
}
]
8 changes: 8 additions & 0 deletions game/chargen/lifepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,14 @@ def __init__(self,name,desc,choices=(),next=(),next_prompt='',auto_fx=None):

STARTING_CHOICES = (A_EARTH,)

STAGE_ORIGIN = "ORIGIN"
STAGE_CHILDHOOD = "CHILDHOOD"
STAGE_VOCATION = "VOCATION"
STAGE_CRISIS = "CRISIS"
STAGE_RESOLUTION = "RESOLUTION"

STAGES = (STAGE_ORIGIN, STAGE_CHILDHOOD, STAGE_VOCATION, STAGE_CRISIS, STAGE_RESOLUTION)

class BioBlock( object ):
def __init__(self,model,width=220,bio_font=None,**kwargs):
self.model = model
Expand Down
1 change: 1 addition & 0 deletions game/content/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(self, camp: gears.GearHeadCampaign, *args, **kwargs):
from . import dungeonmaker

from . import adventureseed
from . import missiontext



Expand Down
101 changes: 101 additions & 0 deletions game/content/ghplots/lancedev.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,107 @@ def lose_mission(self, camp):

# The actual plots...

class HowDoYouLikeThat(LMMissionPlot):
LABEL = "LANCEDEV"
active = True
scope = True
UNIQUE = True

def custom_init(self, nart):
npc = self.seek_element(nart, "NPC", self._is_good_npc, scope=nart.camp.scene, lock=True)
enemy_npc = self.seek_element(nart, "ENEMY_NPC", self._is_good_enemy, scope=nart.camp, lock=True)
other_scene = self.seek_element(nart, "OTHER_SCENE", self._is_good_scene, scope=nart.camp)
self.elements["ENEMY_FACTION"] = enemy_npc.faction
self.prep_mission(nart.camp)
self.started_convo = False
return not nart.camp.are_faction_allies(enemy_npc, npc)

def _is_good_npc(self, nart, candidate):
if self.npc_is_ready_for_lancedev(nart.camp, candidate):
return (
candidate.relationship.attitude == gears.relationships.A_JUNIOR
and candidate.relationship.role == gears.relationships.R_COLLEAGUE
)

def _is_good_enemy(self, nart, candidate):
return (
isinstance(candidate, gears.base.Character) and candidate.combatant and
nart.camp.is_not_lancemate(candidate) and
candidate.relationship and candidate.relationship.is_unfavorable()
)

def _is_good_scene(self, nart, candidate):
return (
isinstance(candidate, gears.GearHeadScene) and gears.tags.SCENE_PUBLIC in candidate.attributes and
candidate.scale is gears.scale.HumanScale
)

def METROSCENE_ENTER(self, camp):
if not self.started_convo:
self.started_convo = True
npc = self.elements["NPC"]
pbge.alert(
"As you enter {METROSCENE}, you notice {NPC} looking at {NPC.gender.possessive_determiner} phone. After a moment {NPC.gender.subject_pronoun} turns to you.".format(
**self.elements))

if npc.get_reaction_score(camp.pc, camp) <= random.randint(20,35):
# NPC has decided to take a better offer. Tough luck.
npc.relationship.attitude = gears.relationships.A_RESENT
npc.relationship.history.append(gears.relationships.Memory(
"I quit your lance after getting a better offer",
"you quit my lance with absolutely no warning",
-10, memtags=(gears.relationships.MEM_Clash, gears.relationships.MEM_Ideological)
))
ghcutscene.SimpleMonologueDisplay(
"[GOODBYE] I just got a better offer to join a different lance. I guess I'll see you around.",
npc)(camp, False)
pbge.alert("And with that, {NPC} quits the lance.".format(**self.elements))
plotutility.AutoLeaver(npc)(camp)
npc.place(self.elements["OTHER_SCENE"], team=self.elements["OTHER_SCENE"].civilian_team)
self.proper_end_plot(camp, False)

else:
npc.relationship.attitude = gears.relationships.A_FRIENDLY
mymenu = ghcutscene.SimpleMonologueMenu(
"I can't believe it! [I_GOT_A_MISSION_OFFER] {ENEMY_NPC} is in town, and I thought you might want to fight {ENEMY_NPC.gender.object_pronoun}.".format(
**self.elements),
npc, camp
)
mymenu.no_escape = True
mymenu.add_item("Of course I do. We've got some scores to settle.", self._accept_offer)
mymenu.add_item("Maybe some other time... I'm not in the mood to deal with {ENEMY_NPC} today.".format(**self.elements), self._reject_offer)
choice = mymenu.query()
if choice:
choice(camp)

def _accept_offer(self, camp):
self.mission_active = True
npc: gears.base.Character = self.elements["NPC"]
ghcutscene.SimpleMonologueDisplay(
"I'm really excited about finding this lead. I think I might be getting the hang of this cavalier thing? [LETSGO]",
npc)(camp, False)
missionbuilder.NewMissionNotification(self.mission_seed.name, self.elements["MISSION_GATE"])

def _reject_offer(self, camp):
npc: gears.base.Character = self.elements["NPC"]
ghcutscene.SimpleMonologueDisplay(
"[UNDERSTOOD] {ENEMY_NPC} can be a [insult]; still, I'm excited to have gotten the call! Maybe I'm getting better at this cavalier stuff.".format(**self.elements),
npc)(camp, False)
self.proper_end_plot(camp)

def prep_mission(self, camp: gears.GearHeadCampaign):
self.mission_seed = missionbuilder.BuildAMissionSeed(
camp, "Find and defeat {ENEMY_NPC}".format(**self.elements),
self.elements["METROSCENE"], self.elements["MISSION_GATE"],
enemy_faction=self.elements.get("ENEMY_FACTION"),
allied_faction=self.elements["METROSCENE"].faction,
rank=camp.renown + 10, objectives=(missionbuilder.BAMO_DEFEAT_NPC,),
cash_reward=self.CASH_REWARD, experience_reward=self.EXPERIENCE_REWARD,
on_win=self.win_mission, on_loss=self.lose_mission,
custom_elements={missionbuilder.BAME_NPC: self.elements["ENEMY_NPC"]}
)


class BetterCallAPlumber(LMMissionPlot):
LABEL = "LANCEDEV"
active = True
Expand Down
5 changes: 5 additions & 0 deletions game/content/ghplots/lancemates.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,11 @@ def _pay_to_join(self, camp):
def _join_lance(self, camp):
npc = self.elements["NPC"]
npc.relationship.tags.add(gears.relationships.RT_LANCEMATE)
npc.relationship.history.append(gears.relationships.Memory(
"I was nearly killed by Typhon",
"you were almost killed by Typhon",
memtags=(gears.relationships.MEM_Trauma,)
))
effect = game.content.plotutility.AutoJoiner(npc)
effect(camp)
self.end_plot(camp)
Expand Down
94 changes: 94 additions & 0 deletions game/content/ghplots/mission_conversations.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,100 @@ def t_UPDATE(self, camp):
self._lose_adventure(camp)


class RalphAndSam(BasicBattleConversation):
UNIQUE = True

@classmethod
def matches(cls, pstate):
return (
pstate.elements["NPC"].relationship and
gears.personality.Cheerful in pstate.elements["NPC"].personality and
pstate.elements["NPC"].relationship.expectation == gears.relationships.E_MERCENARY and
pstate.elements["NPC"].relationship.get_recent_memory([relationships.MEM_Clash]) and
pstate.elements["NPC"].relationship.attitude in (
None, gears.relationships.A_JUNIOR, gears.relationships.A_OPENUP
) and len(pstate.elements["NPC"].relationship.history) >= 3
) or cls.LABEL == "TEST_ENEMY_CONVO"

def NPC_offers(self, camp):
mylist = list()
mylist.append(Offer("[HELLO] We keep running into each other at work... I guess you're playing for the other team again?",
context=ContextTag([context.ATTACK, ]), effect=self._start_conversation))

mylist.append(Offer(
"Remember when [MEM_Clash]? This time I'm going to [defeat_you].",
context=ContextTag([context.COMBAT_CUSTOM, ]),
data={"reply": "Afraid so. [LETSFIGHT]"}, effect=self.friendly_battle
))

mylist.append(Offer(
"Well that's just rude. [CHALLENGE]",
context=ContextTag([context.COMBAT_CUSTOM, ]),
data={"reply": "Do you think this is a game?! [THREATEN]"}, effect=self.unfriendly_battle,
dead_end=True
))

if not self.elements.get(CONVO_CANT_RETREAT, False):
game.ghdialogue.SkillBasedPartyReply(
Offer(
"[REALLY?] Honestly, I don't even care if you're telling the truth or not. I could use a little break. See you around, [audience].",
context=ContextTag([context.COMBAT_CUSTOM]), effect=self.friendly_retreat,
data={"reply": "Actually I'm here to let you know you have the day off."}
), camp, mylist, gears.stats.Charm, gears.stats.Negotiation, self._effective_rank(),
difficulty=gears.stats.DIFFICULTY_LEGENDARY, no_random=False
)

if self._effective_rank() > camp.pc.renown and not self.elements.get(CONVO_CANT_WITHDRAW, False):
mylist.append(Offer(
"Do whatever makes you happy. [GOODBYE]",
context=ContextTag([context.COMBAT_CUSTOM, ]),
data={"reply": "I really don't want to deal with you today. Do you mind if I just leave?"},
effect=self.friendly_withdraw
))

return mylist

def unfriendly_battle(self, camp):
npc: gears.base.Character = self.elements["NPC"]
npc.relationship = camp.get_relationship(npc)
npc.relationship.attitude = relationships.A_RESENT

def friendly_battle(self, camp):
npc: gears.base.Character = self.elements["NPC"]
npc.relationship = camp.get_relationship(npc)
npc.relationship.attitude = relationships.A_FRIENDLY
npc.relationship.history.append(Memory(
"we fought on opposite sides a bunch of times",
"you kept showing up during my missions",
10, memtags=(relationships.MEM_Clash, relationships.MEM_Ideological)
))
self.end_plot(camp, True)

def friendly_retreat(self, camp):
npc: gears.base.Character = self.elements["NPC"]
npc.relationship = camp.get_relationship(npc)
npc.relationship.attitude = relationships.A_FRIENDLY
npc.relationship.history.append(Memory(
"you convinced me to take some time off work",
"you abandoned your mission when I joked about it being a holiday",
10, memtags=(relationships.MEM_Clash, relationships.MEM_CallItADraw)
))
self._enemies_retreat(camp)
self.end_plot(camp, True)

def friendly_withdraw(self, camp):
npc: gears.base.Character = self.elements["NPC"]
npc.relationship = camp.get_relationship(npc)
npc.relationship.attitude = relationships.A_FRIENDLY
npc.relationship.history.append(Memory(
"you let me get off work early when you decided to retreat",
"I wasn't ready to fight you",
20, memtags=(relationships.MEM_Clash, relationships.MEM_DefeatPC)
))
self._player_retreat(camp)
self.end_plot(camp, True)


class AegisInferiorityIntroduction(BasicBattleConversation):
UNIQUE = True

Expand Down
3 changes: 2 additions & 1 deletion game/content/ghplots/missionbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pygame
import random
from game import teams, ghdialogue
from game.content import gharchitecture, ghterrain, ghwaypoints, plotutility
from game.content import gharchitecture, ghterrain, ghwaypoints, plotutility, missiontext
from pbge.dialogue import Offer, ContextTag, Reply
from game.ghdialogue import context
from game.content.ghcutscene import SimpleMonologueDisplay
Expand All @@ -14,6 +14,7 @@
from game.content.dungeonmaker import DG_NAME, DG_ARCHITECTURE, DG_SCENE_TAGS, DG_MONSTER_TAGS, DG_TEMPORARY, \
DG_PARENT_SCENE, DG_EXPLO_MUSIC, DG_COMBAT_MUSIC, DG_DECOR
import copy
from game.content import missiontext

# Mecha Objectives
BAMO_AID_ALLIED_FORCES = "BAMO_AidAlliedForces"
Expand Down
91 changes: 91 additions & 0 deletions game/content/missiontext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import random

import gears
from game.content.ghplots import missionbuilder

MOTIVE_ATTACK = "ATTACK"
MOTIVE_DEFEND = "DEFEND"
MOTIVE_GREED = "GREED"
MOTIVE_REVENGE = "REVENGE"
MOTIVE_RECON = "RECON"

MEANS_OFFENSE = "OFFENSE"
MEANS_STEAL = "STEAL"
MEANS_INFILTRATE = "INFILTRATE"
MEANS_FORTIFY = "FORTIFY"


class MissionText:

def __init__(self, camp: gears.GearHeadCampaign, objectives, metroscene, allied_faction=None, enemy_faction=None):
# Give us some text that can be used to generate a MissionGrammar and also some text that can be used by the
# mission-giver to describe the mission.
motive_candidates = list()
means_candidates = list()
if {
missionbuilder.BAMO_AID_ALLIED_FORCES, missionbuilder.BAMO_DEFEAT_ARMY,
missionbuilder.BAMO_DEFEAT_COMMANDER, missionbuilder.BAMO_DESTROY_ARTILLERY,
missionbuilder.BAMO_LOCATE_ENEMY_FORCES, missionbuilder.BAMO_RESPOND_TO_DISTRESS_CALL,
}.intersection(objectives):
means_candidates.append(MEANS_OFFENSE)
if enemy_faction and camp.are_faction_allies(metroscene, enemy_faction):
motive_candidates.append(MOTIVE_DEFEND)
elif enemy_faction and gears.tags.Criminal in enemy_faction.factags:
motive_candidates.append(MOTIVE_GREED)

if {
missionbuilder.BAMO_DEFEAT_THE_BANDITS, missionbuilder.BAMO_RECOVER_CARGO,
missionbuilder.BAMO_CAPTURE_THE_MINE, missionbuilder.BAMO_PROTECT_BUILDINGS,
missionbuilder.BAMO_RESPOND_TO_DISTRESS_CALL, missionbuilder.BAMO_SURVIVE_THE_AMBUSH,
}.intersection(objectives):
means_candidates.append(MEANS_STEAL)
motive_candidates.append(MOTIVE_GREED)
if enemy_faction and {gears.tags.Military, gears.tags.CorporateWorker}.intersection(enemy_faction.factags):
motive_candidates.append(MOTIVE_RECON)
if enemy_faction and {gears.tags.Criminal, gears.tags.CorporateWorker}.intersection(enemy_faction.factags):
means_candidates.append(MEANS_STEAL)

if {
missionbuilder.BAMO_EXTRACT_ALLIED_FORCES, missionbuilder.BAMO_AID_ALLIED_FORCES,
missionbuilder.BAMO_SURVIVE_THE_AMBUSH, missionbuilder.BAMO_LOCATE_ENEMY_FORCES,
missionbuilder.BAMO_DEFEAT_NPC, missionbuilder.BAMO_RESCUE_NPC, missionbuilder.BAMO_SURVIVE_THE_AMBUSH,
}.intersection(objectives):
means_candidates.append(MEANS_INFILTRATE)
motive_candidates.append(MOTIVE_RECON)
if enemy_faction and gears.tags.Criminal in enemy_faction.factags:
motive_candidates.append(MOTIVE_GREED)

if {
missionbuilder.BAMO_CAPTURE_BUILDINGS, missionbuilder.BAMO_CAPTURE_THE_MINE,
missionbuilder.BAMO_DESTROY_ARTILLERY, missionbuilder.BAMO_STORM_THE_CASTLE,
missionbuilder.BAMO_DEFEAT_ARMY, missionbuilder.BAMO_NEUTRALIZE_ALL_DRONES,
}.intersection(objectives):
means_candidates.append(MEANS_FORTIFY)
if enemy_faction and camp.are_faction_allies(metroscene, enemy_faction):
motive_candidates.append(MOTIVE_DEFEND)
else:
motive_candidates.append(MOTIVE_ATTACK)
if enemy_faction and {gears.tags.Politician, gears.tags.CorporateWorker}.intersection(enemy_faction.factags):
motive_candidates.append(MOTIVE_DEFEND)

if camp.are_faction_enemies(metroscene, enemy_faction):
motive_candidates.append(MOTIVE_ATTACK)

if enemy_faction and gears.tags.Military in enemy_faction.factags and not camp.are_faction_allies(enemy_faction, metroscene):
motive_candidates.append(MOTIVE_ATTACK)

if camp.are_faction_enemies(allied_faction, enemy_faction):
motive_candidates.append(MOTIVE_REVENGE)

if enemy_faction and gears.tags.Criminal in enemy_faction.factags:
motive_candidates.append(MOTIVE_GREED)

if not motive_candidates:
motive_candidates = [MOTIVE_ATTACK, MOTIVE_GREED, MOTIVE_RECON]

if not means_candidates:
means_candidates = [MEANS_OFFENSE, MEANS_INFILTRATE]

motive = random.choice(motive_candidates)
means = random.choice(means_candidates)

11 changes: 11 additions & 0 deletions game/exploration.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,17 @@ def go(self):
if hasattr(pc, "relationship") and pc.relationship and hasattr(pc, "renown"):
print("{} {} {} OK:{}".format(pc, pc.renown, pc.relationship.hilights(),
pc.relationship.can_do_development()))
elif gdi.unicode == "N" and pbge.util.config.getboolean("GENERAL", "dev_mode_on"):
print("Checking Enemies")
enemies = [candidate for candidate in self.camp.all_contents(self.camp) if (
isinstance(candidate, gears.base.Character) and candidate.combatant and
candidate.relationship and candidate.relationship.is_unfavorable()
)]
for pc in enemies:
if hasattr(pc, "relationship") and pc.relationship and hasattr(pc, "renown"):
print("{} ({}): {}\n --{}\n --Renown {}, {}\n --Memories: {}".format(pc, pc.faction, pc.get_text_desc(self.camp), pc.get_tags(False), pc.renown, pc.relationship.hilights(), len(pc.relationship.history)))
for mem in pc.relationship.history:
print(mem)
elif gdi.unicode == "V" and pbge.util.config.getboolean("GENERAL", "dev_mode_on"):
for pc in list(self.camp.party):
if pc in self.scene.contents and isinstance(pc,
Expand Down
Loading

0 comments on commit c30a5cb

Please sign in to comment.