Skip to content

Instantly share code, notes, and snippets.

@frosch123
Forked from TrueBrain/MyTownMod.py
Last active April 14, 2019 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frosch123/2d36e092815df797e3dfc9bd4cff11b0 to your computer and use it in GitHub Desktop.
Save frosch123/2d36e092815df797e3dfc9bd4cff11b0 to your computer and use it in GitHub Desktop.
My Town Mod
class AggressiveTown(Town):
class table:
pass
class actions:
bribe = Action(String("Bribe"), AggressiveTown._onActionBribe)
grow_town = Action(String("Grow town"), AggressiveTown._onActionGrowTown)
class storage:
CATS_LAST_DELIVERED: Date
CITY_XMAS: bool
ELECTRICITY_SUPPLY_LEVEL: int
GAS_UNDERGROUND: bool
MY_HOUSE_LOCATION: Location
PISSED: bool
YUMMINESS: int
class client_storage:
LAST_COMMAND: int = 0
def _onActionBribe(town) -> None:
town.storage.PISSED = False
town.actions.grow_town.disabled = None
def _onActionGrowTown(town) -> None:
town.api.GrowTown()
def _make_pissed(town):
town.storage.PISSED = True
town.actions.grow_town.disabled = String("The town is pissed at you")
class Electricity:
class Event(Town.Event):
town: AggressiveTown
def onTick(event) -> None:
electricity_supply_level = 0
for industry in event.town.api.GetIndustries():
amount = industry.api.GetProduction(Cargo.ELECTRICITY)
if amount:
electricity_supply_level += amount
if electricity_supply_level > 10:
event.town.storage.ELECTRICITY_SUPPLY_LEVEL = 2
elif electricity_supply_level > 0:
event.town.storage.ELECTRICITY_SUPPLY_LEVEL = 1
else:
event.town.storage.ELECTRICITY_SUPPLY_LEVEL = 0
class Cats:
class Event(Town.Event):
town: AggressiveTown
def onDelivery(event, cargo, amount) -> None:
if cargo == Cargo.CATS:
if event.town.storage.CATS_LAST_DELIVERED - tools.today() < 30:
event.town.api.SetPrice(Cargo.CATS, event.town.api.GetPrice(Cargo.CATS) - 10)
event.town.storage.CATS_LAST_DELIVERED = tools.today()
class Timer(Town.Timer):
town: AggressiveTown
interval = tools.DAY * 10
repeat = Timer.REPEAT_ALWAYS
def onCall(timer) -> None:
if timer.town.api.CountIndustries(type='cat_farm') < 3:
timer.town.api.CreateIndustry('cat_farm')
class TimerCat(Town.Timer):
town: AggressiveTown
interval = tools.DAY * 30
repeat = Timer.REPEAT_ALWAYS
def onCall(timer) -> None:
if timer.town.storage.CATS_LAST_DELIVERED - tools.today() >= 30:
timer.town.api.SetPrice(Cargo.CATS, min(timer.town.api.GetPrice(Cargo.CATS) + 20, timer.town.api.GetDefaultPrice(Cargo.CATS)))
class Pissed:
class Event(Town.Event):
town: AggressiveTown
def onPlace(event) -> None:
event.town.storage.PISSED = False
def onDemolish(event, location) -> None:
if location == event.town.storage.MY_HOUSE_LOCATION:
event.town._make_pissed()
class Timer(Town.Timer):
town: AggressiveTown
interval = tools.DAY * 10
repeat = Timer.REPEAT_ALWAYS
def onCall(timer) -> None:
if timer.town.api.GetTransportedCargos(Cargo.TRASH) < timer.town.api.GetProducedCargos(Cargo.TRASH) / 4:
timer.town._make_pissed()
class Client(Town.Client):
town: AggressiveTown
@priority(1)
def GUI(client) -> List[Any]:
res: List[Any] = []
if client.town.storage.PISSED:
res.append(String("What have you done?! WE ARE PISSED"))
return res
class Yumminess:
class Event(Town.Event):
town: AggressiveTown
def onTick(event) -> None:
if event.town.storage.YUMMINESS > 10 and event.town.storage.ELECTRICITY_SUPPLY_LEVEL > 0:
event.town.api.GrowTown()
event.town.storage.YUMMINESS -= 10
event.town.api.ChangeZone(Location(-1, 0), Zone.SUBURBS)
def onDelivery(event, cargo, amount) -> None:
if cargo == Cargo.CHEESE:
event.town.storage.YUMMINESS += amount
class Client(Town.Client):
town: AggressiveTown
@priority(2)
def GUI(client) -> List[Any]:
res: List[Any] = []
if client.town.storage.YUMMINESS <= 10:
res.append(String("More cheese please :)"))
return res
class Christmas:
class Event(Town.Event):
town: AggressiveTown
def onTick(event) -> None:
if tools.today().month in [11, 12]:
event.town.storage.CITY_XMAS = True
else:
event.town.storage.CITY_XMAS = False
class Hook(Town.Hook):
town: AggressiveTown
@priority(1)
def canCreateIndustry(hook, type) -> bool:
if hook.town.storage.CITY_XMAS:
return False
raise NextHook
class GasWell:
class Hook(Town.Hook):
town: AggressiveTown
@priority(2)
def canCreateIndustry(hook, type) -> bool:
return hook.town.storage.GAS_UNDERGROUND and hook.town.api.CountIndustries(type='gas_well') < 3
class ButtonExample:
class Client(Town.Client):
town: AggressiveTown
@priority(3)
def GUI(client) -> List[Any]:
res: List[Any] = []
if client.town.client_storage.LAST_COMMAND == 0:
res.append(Button("Click", AggressiveTown.ButtonExample.Client._onClickButton))
return res
def onCommand(client, command: int):
client.town.client_storage.LAST_COMMAND = command
def _onClickButton(client):
client.SendCommand(1)
class Server(Town.Server):
town: AggressiveTown
def onCommand(server, command: int):
server.SendCommand(1)
class MyHouse(House):
town: AggressiveTown
class table:
dimension = Dimension(2, 2)
flags = House.Flags.ONLY_SCENARIO_EDITOR | House.Flags.ONE_PER_TOWN
population = 12
accept_cargo = {
Cargo.MAIL: 8
}
class Event(House.Event):
house: MyHouse
def onPlace(event) -> None:
event.house.town.storage.MY_HOUSE_LOCATION = event.house.location
def onTick(event) -> None:
if tools.random() < event.house.town.population:
event.house.api.MoveGoodsToStation(Cargo.PASSENGERS, 100, event.house.town)
class Hook(House.Hook):
house: MyHouse
def getSprite(hook, offset: Offset) -> Sprite:
if hook.house.town.api.GetZone(hook.house.location) == Zone.SUBURBS:
return Sprite("myhouse_suburbs.png", offset.x * 50, offset.y * 50, 50, 50)
if hook.house.town.storage.CITY_XMAS:
return Sprite("myhouse_city_xmas.png", offset.x * 50, offset.y * 50, 50, 50)
return Sprite("myhouse_city.png", offset.x * 50, offset.y * 50, 50, 50)
# This examples tries to bake the server/client architecture into the API.
# It tries to separate synchronous and deterministic code from asynchronous and random stuff.
class TrapTown(Town.Agent):
# GameState is used to define variables which belong to the GameState.
# - Stored in savegames.
# - Transfered to joining clients.
# - Can be read by everyone on server and client at any time.
# - Can only be changed in Synchronous Hooks or Commands.
cats_last_delivered = Town.GameState(Date) # Variable per town
electricity_supply_level = Town.GameState(int)
is_pissed = Town.GameState(CompanyDict[bool]) # Variable per town and company. Bankrupt companies are removed from the dict.
# ServerState is used to define variables that are only known on the server
# - Stored in server-side savegames.
# - Not transfered to joining clients.
# - Can be read and modified by the server at any time.
# - Unknown to clients.
secret_beartrap = Town.ServerState(TileIndex) # Server-side variable per town.
# Define some commands for server/client interaction
cmd_install_trap = Town.Command(CMDT_LANDSCAPE_CONSTRUCTION)
cmd_disarm_trap = Town.Command(CMDT_LANDSCAPE_CONSTRUCTION)
cmd_trigger_trap = Town.Command(CMDT_LANDSCAPE_CONSTRUCTION, CMD_DEITY)
@cmd_install_trap.Execute
def CmdInstallTrap(param, testrun):
# Executed on both client and server
if not testrun:
if Random(20, seed=GameState) == 0: # Random seed synchronised
is_pissed[param.company] = True
else if is_server:
secret_beartrap = TileArea.Circle(Town.center_tile, 10).RandomTile(seed=ServerState) # Random seed server-only
return Cost(10000, PR_TOWN_ACTION)
@cmd_disarm_trap.Execute
def CmdDisarmTrap(param, testrun):
# Executed on both client and server
if not testrun:
is_pissed[param.company] = False
if is_server:
secret_beartrap = None
return Cost(100000, PR_TOWN_ACTION)
@OpenTTD.CmdLandscapeClear.Execute
def CmdLandscapeClear(param, testrun):
# Executed on both client and server
if not testrun and is_server:
if secret_beartrap and secret_beartrap == param.tile:
# Boom
secret_beartrap = None
# The following must be done on all clients as well, so issue additional deity command.
cmd_trigger_trap.Emit(tile = param.tile, punished_company = param.company)
return Cost()
@cmd_trigger_trap.Execute
def CmdTriggerTrap(param, testrun):
# Executed on both client and server, triggered only by server/deity
is_pissed[param.punished_company] = True
for t in TileArea.Circle(param.tile, 10):
CmdLandscapeClear.Emit(t)
class TrapGUI(Town.GUI):
def __init__(self):
# Executed when Town GUI is opened
self.btn_install = Button(gui_container, "Install trap")
@self.btn_install.Press
def ButtonInstall:
TrapTown.cmd_install_trap.Emit(town = town)
self.btn_disarm = Button(gui_container, "Search and disarm")
@self.btn_disarm.Press
def ButtonDisarm:
TrapTown.cmd_disarm_trap.Emit(town = town)
@TrapTown.cmd_disarm_trap.Execute
def OnCmdDisarm():
self.InvalidateGUI()
@OpenTTD.CmdLandscapeClear.Execute
def OnCmdLandscapeClear():
self.InvalidateGUI()
self.InvalidateGUI()
def InvalidateGUI(self):
available = Client.Company and not TrapTown.is_pissed.get(Client.Company, False)
self.btn_install.SetEnabled(available)
self.btn_disarm.SetEnabled(available)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment