-
-
Save frosch123/2d36e092815df797e3dfc9bd4cff11b0 to your computer and use it in GitHub Desktop.
My Town Mod
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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