Documentation ¶
Index ¶
- Constants
- Variables
- func CharacterToPlayer(c *models.Character) (*Entity, *Coordinates, error)
- func ExecuteCommand(c *Client, msg string)
- func GenerateCities() map[string]*City
- func GenerateItemsList()
- func HandleWsClient(g *Game, w http.ResponseWriter, r *http.Request)
- func LinkRanks()
- type ActionType
- type Building
- type BuildingGameFrame
- type BuildingLocation
- type BuildingTemplate
- type BuildingType
- type CheckNameBody
- type CheckNameResponse
- type City
- type CityTemplate
- type Client
- type ClientResponse
- type CombatAction
- type Command
- type Coordinates
- type Entity
- func (n *Entity) ClearStock()
- func (n *Entity) Death(killer *Entity)
- func (p *Entity) GangTag() string
- func (n *Entity) NPCAttack()
- func (n *Entity) NPCFindTarget() (*Entity, bool)
- func (n *Entity) NPCGameFrame() *responses.NPC
- func (n *Entity) NPCMove()
- func (n *Entity) NPCStartRoutines()
- func (e *Entity) OpenDrugDealer(c *Client)
- func (e *Entity) OpenDruggieMenu(c *Client)
- func (p *Entity) PlayerGameFrame() *responses.Player
- func (p *Entity) PlayerGetBuildingCommand(cmdKey string) (*Command, bool)
- func (p *Entity) PlayerSendInventoryUpdate()
- func (p *Entity) PlayerSendLocationUpdate()
- func (p *Entity) PlayerSendMapUpdate()
- func (p *Entity) PlayerSendPlayerList()
- func (p *Entity) PlayerSendStatsUpdate()
- func (e *Entity) RandomiseGenderName()
- func (n *Entity) RemoveTargetLock()
- func (n *Entity) Restock()
- func (e *Entity) Save()
- func (e *Entity) StartRoutines()
- func (e *Entity) SyncDealerInventory(c *Client)
- func (e *Entity) SyncDruggieTrade(c *Client)
- type Game
- func (g *Game) CheckNameTaken(w http.ResponseWriter, r *http.Request)
- func (g *Game) GetGang(gangId uint64) (*Gang, error)
- func (g *Game) GetPlayerClient(playerId uint64) *Entity
- func (g *Game) GetUserCharacter(userId uint64) (*Entity, *Coordinates, error)
- func (g *Game) HandleLogout(client *Client)
- func (g *Game) HandleRegistration(w http.ResponseWriter, r *http.Request)
- func (g *Game) LoginPlayer(c *Client, p *Entity, k *Coordinates)
- func (g *Game) RenderConsoleUI()
- func (g *Game) Restock()
- func (g *Game) Run()
- func (g *Game) Save()
- func (g *Game) SendMOTD(c *Client)
- type Gang
- type Gender
- type IType
- type Inventory
- type Item
- func (g *Item) GameFrame() *responses.Item
- func (i *Item) GetAmmoWear() float32
- func (i *Item) GetArmorGuns() uint
- func (i *Item) GetArmorMelee() uint
- func (i *Item) GetDamage() uint
- func (i *Item) GetDescription() string
- func (i *Item) GetItemStats() []string
- func (i *Item) GetItemType() IType
- func (i *Item) GetMinRep() int64
- func (i *Item) GetName() string
- func (i *Item) GetPrice() uint32
- func (i *Item) GetQualitySuffix() string
- func (i *Item) GetUseEffect() *ItemUseEffect
- func (g *Item) InspectName() string
- func (i *Item) IsGear() bool
- type ItemGameFrame
- type ItemMoved
- type ItemSaveContainer
- type ItemTemplate
- type ItemUseEffect
- type KeyFloatValue
- type KeyIntValue
- type KeyStringValue
- type Location
- type Movement
- type NPCGameFrame
- type NPCType
- type NpcTemplate
- type PlayerGameFrame
- type Rank
- type RegistrationBody
- type RegistrationResponse
- type StockItem
Constants ¶
View Source
const ( CombatActionAim = 1 CombatActionPunch = 2 CombatActionStrike = 3 CombatActionShoot = 4 CombatActionDeath = 5 CombatActionFlee = 6 )
View Source
const ( ItemTypeTrash = 0 ItemTypeGun = 1 ItemTypeMelee = 2 ItemTypeArmor = 3 ItemTypeAmmo = 4 ItemTypeSmartPhone = 5 ItemTypeDrug = 6 ItemTypeLabel = 6 ItemTypeMystery = 7 )
Variables ¶
View Source
var ( ItemsList = map[string]*Item{} DrugsList = []*Item{} )
View Source
var BuildingCommandsList = map[string]*Command{ "/shop": { Args: []string{"name"}, Description: "Opens the shop's trade menu", AllowInGame: true, Help: func(c *Client) { headings := []string{"Example", "Description"} lines := [][]string{ {"/shop", "Will open the first found shop in the area."}, {"/shop <name>", "Will open the first sho beginning with the name."}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, lines), }) }, Call: func(c *Client, args []string) { if c.Player == nil { return } var building *Building var altBuilding *Building name := "" if len(args) > 0 { name = strings.ToLower(args[0]) } for _, b := range c.Player.Loc.Buildings { if b.ShopStock != nil && len(b.ShopStock) > 0 || b.ShopBuyType != nil && len(b.ShopBuyType) > 0 { altBuilding = b if strings.HasPrefix(strings.ToLower(b.Name), name) { building = b break } } } if building == nil { building = altBuilding if building == nil { c.SendEvent(&responses.Generic{ Messages: []string{"There are no shops around here by that name"}, }) return } } building.OpenShop(c) }, }, "/drink": { Args: []string{"amount"}, Description: "Drink and buy rounds to increase you reputation.", Example: "/drink 10", AllowInGame: true, Call: func(c *Client, args []string) { if len(args) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"Missing amount. Try: /drink help"}, }) return } amount, err := strconv.ParseInt(args[0], 10, 32) if err != nil || amount < 1 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid amount. Try: /drink help"}, }) return } health_cost := int(amount * settings.DrinkHealthCost) drink_cost := int64(amount * settings.DrinkCost) rep_gain := int64(amount * settings.DrinkRepGain) if c.Player.Cash < drink_cost { c.SendEvent(&responses.Generic{ Messages: []string{"You do not have enough money on you"}, }) return } if c.Player.Health <= health_cost { c.SendEvent(&responses.Generic{ Messages: []string{"Don't be stupid, that will kill you."}, }) return } c.Player.Cash -= drink_cost c.Player.Health -= health_cost c.Player.Reputation += rep_gain c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{fmt.Sprintf("You spend %d on buying drinks and paying for strippers, your reputation increased by %d", drink_cost, rep_gain)}, }) go c.Player.PlayerSendStatsUpdate() }, Help: func(c *Client) { headings := []string{"Example", "Health Cost", "$ Cost", "Rep Gain"} lines := [][]string{ {"/drink 1", fmt.Sprintf("%d", settings.DrinkHealthCost), fmt.Sprintf("%d", settings.DrinkCost), fmt.Sprintf("%d", settings.DrinkRepGain)}, {"/drink 5", fmt.Sprintf("%d", 5*settings.DrinkHealthCost), fmt.Sprintf("%d", 5*settings.DrinkCost), fmt.Sprintf("%d", 5*settings.DrinkRepGain)}, {"/drink 10", fmt.Sprintf("%d", 10*settings.DrinkHealthCost), fmt.Sprintf("%d", 10*settings.DrinkCost), fmt.Sprintf("%d", 10*settings.DrinkRepGain)}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, lines), }) }, }, "/transfer": { Args: []string{"user", "amount"}, Description: "Transfer money from your bank account to another.", Example: "/transfer <User> 100", AllowInGame: true, Call: func(c *Client, args []string) { if c.Player.Hometown != c.Player.Loc.City.ShortName { c.SendEvent(&responses.Generic{ Messages: []string{"You can only use the bank to withdraw money when you are not in your home city."}, }) return } username := args[0] amount, err := strconv.ParseInt(args[1], 10, 32) if err != nil || amount < 1 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid amount. Try: /transfer <username> <amount>"}, }) return } c.Player.Mu.Lock() defer c.Player.Mu.Unlock() if amount > c.Player.Bank { c.SendEvent(&responses.Generic{ Messages: []string{"You don't have that much money in your bank account."}, }) return } var player *Entity for tc := range c.Game.Clients { if tc.Player == nil { return } if strings.ToLower(tc.Player.Name) == username { player = tc.Player break } } if player == nil { c.SendEvent(&responses.Generic{ Messages: []string{"We cannot find anyone going by that name."}, }) return } player.Mu.Lock() defer player.Mu.Unlock() c.Player.Bank -= amount player.Bank += amount c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("You just transferred $%d to %s", amount, player.Name)}, }) player.Client.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("%s just transferred you $%d", c.Player.Name, amount)}, }) logger.LogMoney(c.Player.Name, "transfer", amount, player.Name) }, }, "/deposit": { Args: []string{"amount"}, Description: "Deposit money in your bank account.", Example: "/deposit 100", AllowInGame: true, Call: func(c *Client, args []string) { if c.Player.Hometown != c.Player.Loc.City.ShortName { c.SendEvent(&responses.Generic{ Messages: []string{"You can only use the bank to withdraw money when you are not in your home city."}, }) return } if len(args) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"Missing amount. Try: /deposit help"}, }) return } amount, err := strconv.ParseInt(args[0], 10, 32) if err != nil || amount < 1 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid amount. Try: /deposit help"}, }) return } if c.Player.Cash < amount { c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("You do not have %d on you", amount)}, }) return } logger.LogMoney(c.Player.Name, "bank-pre-statement", c.Player.Bank, "") c.Player.Cash -= amount c.Player.Bank += amount logger.LogMoney(c.Player.Name, "deposit", amount, "") logger.LogMoney(c.Player.Name, "bank-post-statement", c.Player.Bank, "") c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{fmt.Sprintf("You deposit $%d in your bank account.", amount)}, }) go c.Player.PlayerSendStatsUpdate() }, Help: func(c *Client) { headings := []string{"Example", ""} lines := [][]string{ {"/deposit 100", "Deposits $100"}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, lines), }) }, }, "/withdraw": { Args: []string{"amount"}, Description: "Withdraw money from your bank account.", Example: "/withdraw 100", AllowInGame: true, Call: func(c *Client, args []string) { if len(args) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"Missing amount. Try: /withdraw help"}, }) return } argAmount, err := strconv.ParseInt(args[0], 10, 32) if err != nil || argAmount < 1 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid amount. Try: /withdraw help"}, }) return } amount := argAmount if c.Player.Bank < amount { c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("You do not have $%d in the bank", amount)}, }) return } logger.LogMoney(c.Player.Name, "bank-pre-statement", c.Player.Bank, "") logger.LogMoney(c.Player.Name, "withdraw", amount, "") c.Player.Bank -= amount c.Player.Cash += amount c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{fmt.Sprintf("You withdraw $%d from your account.", amount)}, }) logger.LogMoney(c.Player.Name, "bank-post-statement", c.Player.Bank, "") go c.Player.PlayerSendStatsUpdate() }, Help: func(c *Client) { headings := []string{"Example", ""} lines := [][]string{ {"/withdraw 100", "Withdraws $100"}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, lines), }) }, }, "/heal": { Args: []string{"amount"}, Description: "You can heal up here.", Example: "/heal 12", AllowInGame: true, Call: func(c *Client, args []string) { if len(args) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"Missing amount. Try: /heal help"}, }) return } if c.Player.Health >= settings.PlayerMaxHealth { c.SendEvent(&responses.Generic{ Messages: []string{"You do not need any patching up, you are at full health"}, }) return } amount, err := strconv.ParseInt(args[0], 10, 32) if err != nil || amount < 1 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid amount. Try: /heal help"}, }) return } healAmount := int(amount) if healAmount > settings.PlayerMaxHealth-c.Player.Health { healAmount = settings.PlayerMaxHealth - c.Player.Health } healCost := int64(healAmount * settings.HealCostPerPoint) if c.Player.Cash < healCost { c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("You do not have enough money. Costs %d per point to heal", settings.HealCostPerPoint)}, }) return } c.Player.Cash -= healCost c.Player.Health += healAmount if c.Player.Health > settings.PlayerMaxHealth { c.Player.Health = settings.PlayerMaxHealth } c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{fmt.Sprintf("You pay the doctor %d to patch you up.", healAmount*settings.HealCostPerPoint)}, }) go c.Player.PlayerSendStatsUpdate() }, Help: func(c *Client) { headings := []string{"Example", "Cost per HP", "Total Cost"} lines := [][]string{ {"/heal 10", fmt.Sprintf("%d", settings.HealCostPerPoint), fmt.Sprintf("%d", 10*settings.HealCostPerPoint)}, {"/heal 43", fmt.Sprintf("%d", settings.HealCostPerPoint), fmt.Sprintf("%d", 43*settings.HealCostPerPoint)}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, lines), }) }, }, "/travel": { Args: []string{"destination"}, Description: "travel to another city. /travel help for destinations", Example: "/travel lon", AllowInGame: true, Call: func(c *Client, args []string) { if len(args) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"Missing destination. Try: /travel help"}, }) return } city, ok := c.Game.World[strings.ToUpper(args[0])] if !ok { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid destination. Try: /travel help"}, }) return } if c.Player.Cash < city.TravelCost { c.SendEvent(&responses.Generic{ Messages: []string{"You do not have enough cash on you"}, }) return } c.Player.Cash -= city.TravelCost for _, poi := range city.POILocations { if poi.POIType == BuildingTypeAirport { city.Grid[poi.toString()].PlayerJoin <- c c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{"You fly off to your destination"}, }) go c.Player.PlayerSendStatsUpdate() } } }, Help: func(c *Client) { headings := []string{"Destination", "Cost", "Command"} lines := [][]string{} for _, city := range c.Game.World { lines = append(lines, []string{ city.Name, fmt.Sprintf("%d", city.TravelCost), fmt.Sprintf("/travel %s", city.ShortName), }) } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, lines), }) }, }, }
View Source
var BuildingTemplates = map[BuildingType]BuildingTemplate{ BuildingTypeAirport: { Name: "International Airport", Commands: []string{ "/travel", }, }, BuildingTypeHospital: { Name: "Private Hospital", Commands: []string{ "/heal", }, }, BuildingTypeBank: { Name: "City Bank", Commands: []string{ "/withdraw", "/deposit", "/transfer", }, }, BuildingTypeBar: { Name: "Old Speakeasy", Commands: []string{ "/drink", }, }, BuildingTypePawnShop: { Name: "Pawn Shop", MerchantType: responses.MerchantType_MERCHANT_PAWN_SHOP, Commands: []string{ "/shop", }, ShopStock: map[string]int32{ "smartphone": -1, }, ShopBuyType: map[IType]int32{ ItemTypeMelee: -1, ItemTypeSmartPhone: -1, ItemTypeTrash: -1, }, }, BuildingTypeArms: { Name: "Arms Dealer", MerchantType: responses.MerchantType_MERCHANT_ARMS_DEALER, Commands: []string{ "/shop", }, ShopStock: map[string]int32{ "iia_armor": -1, "ii_armor": -1, "iiia_armor": -1, "iii_armor": -1, "iv_armor": -1, "stabvest": -1, "chainmail": -1, "hardarmor": -1, "subsonic": -1, "sdammo": -1, "plusp": -1, "pluspplus": -1, "apammo": -1, "beretta92": -1, "glock22": -1, "sigp320": -1, "sw610": -1, "1911": -1, "ragingbull": -1, "ar-15": -1, "ak47": -1, "scarh": -1, "m82": -1, "brassknuckle": -1, "pipewrench": -1, "crowbar": -1, "switchblade": -1, "bbbat": -1, "fireaxe": -1, "machete": -1, "katana": -1, "chainsaw": -1, }, ShopBuyType: map[IType]int32{ ItemTypeGun: -1, ItemTypeAmmo: -1, ItemTypeArmor: -1, ItemTypeMelee: -1, ItemTypeSmartPhone: -1, }, }, }
View Source
var CityTemplates = []CityTemplate{ { Name: "Beijing", ShortName: "BJ", Width: 30, Height: 30, TravelCostMin: 800, TravelCostMax: 1200, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 29, East: 20, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 12, East: 4, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 29, East: 21, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 6, East: 17, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 25, East: 10, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 8, East: 30, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Tokyo", ShortName: "TY", Width: 30, Height: 30, TravelCostMin: 800, TravelCostMax: 1200, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 28, East: 4, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 12, East: 27, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 18, East: 8, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 24, East: 5, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 6, East: 15, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 9, East: 22, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Moscow", ShortName: "MC", Width: 30, Height: 30, TravelCostMin: 240, TravelCostMax: 600, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 3, East: 29, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 16, East: 11, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 5, East: 19, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 23, East: 1, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 7, East: 21, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 28, East: 15, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Jakata", ShortName: "JK", Width: 30, Height: 30, TravelCostMin: 900, TravelCostMax: 1300, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 20, East: 12, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 12, East: 27, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 8, East: 18, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 29, East: 3, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 14, East: 21, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 4, East: 7, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Mexico City", ShortName: "MX", Width: 30, Height: 30, TravelCostMin: 300, TravelCostMax: 600, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 5, East: 18, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 14, East: 27, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 9, East: 8, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 20, East: 4, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 2, East: 25, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 15, East: 18, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "London", ShortName: "LD", Width: 30, Height: 30, TravelCostMin: 600, TravelCostMax: 900, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 1, East: 24, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 23, East: 17, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 10, East: 6, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 29, East: 14, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 7, East: 29, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 25, East: 19, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Berlin", ShortName: "BL", Width: 30, Height: 30, TravelCostMin: 200, TravelCostMax: 400, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 14, East: 26, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 23, East: 10, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 12, East: 26, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 5, East: 19, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 30, East: 7, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 8, East: 29, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Madrid", ShortName: "MD", Width: 30, Height: 30, TravelCostMin: 600, TravelCostMax: 900, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 14, East: 8, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 12, East: 22, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 5, East: 17, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 30, East: 3, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 7, East: 10, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 14, East: 9, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Pretoria", ShortName: "PT", Width: 30, Height: 30, TravelCostMin: 1200, TravelCostMax: 1800, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 24, East: 3, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 17, East: 12, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 28, East: 30, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 6, East: 3, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 19, East: 21, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 10, East: 29, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Rome", ShortName: "RO", Width: 30, Height: 30, TravelCostMin: 200, TravelCostMax: 400, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 21, East: 18, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 22, East: 5, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 13, East: 18, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 7, East: 26, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 30, East: 2, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 25, East: 14, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Paris", ShortName: "PA", Width: 30, Height: 30, TravelCostMin: 400, TravelCostMax: 900, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 19, East: 12, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 8, East: 27, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 16, East: 10, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 30, East: 15, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 4, East: 3, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 19, East: 22, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Warsaw", ShortName: "WS", Width: 30, Height: 30, TravelCostMin: 200, TravelCostMax: 400, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 24, East: 7, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 11, East: 20, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 5, East: 9, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 28, East: 6, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 23, East: 12, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 2, East: 29, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Stockholm", ShortName: "SH", Width: 30, Height: 30, TravelCostMin: 200, TravelCostMax: 400, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 27, East: 12, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 18, East: 7, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 1, East: 30, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 14, East: 23, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 10, East: 19, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 26, East: 2, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "New York City", ShortName: "NY", Width: 30, Height: 30, TravelCostMin: 500, TravelCostMax: 900, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 25, East: 19, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 9, East: 16, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 21, East: 8, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 3, East: 27, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 24, East: 13, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 15, East: 12, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, { Name: "Las Vegas", ShortName: "LV", Width: 30, Height: 30, TravelCostMin: 300, TravelCostMax: 600, NpcSpawnList: map[NPCType]uint8{ DrugDealer: 2, DrugAddict: 2, Homeless: 6, Tweaker: 2, Bouncer: 2, Busker: 3, StreetVendor: 4, StreetGangMember: 2, Tourist: 5, Activist: 5, PoliceOfficer: 3, BeatCop: 2, DeliveryDriver: 4, }, BuildingLocations: []BuildingLocation{ { Coords: Coordinates{ North: 30, East: 13, }, Buildings: []BuildingType{ BuildingTypePawnShop, }, }, { Coords: Coordinates{ North: 12, East: 25, }, Buildings: []BuildingType{ BuildingTypeAirport, }, }, { Coords: Coordinates{ North: 17, East: 11, }, Buildings: []BuildingType{ BuildingTypeHospital, }, }, { Coords: Coordinates{ North: 29, East: 6, }, Buildings: []BuildingType{ BuildingTypeArms, }, }, { Coords: Coordinates{ North: 4, East: 21, }, Buildings: []BuildingType{ BuildingTypeBank, }, }, { Coords: Coordinates{ North: 7, East: 14, }, Buildings: []BuildingType{ BuildingTypeBar, }, }, }, }, }
View Source
var CommandAliases = map[string]string{
"/get": "/pickup",
"/p": "/pickup",
"/w": "/pm",
"/h": "/help",
"/s": "/say",
"/g": "/global",
"/m": "/move",
"/r": "/refresh",
"/b": "/buy",
}
View Source
var CommandsList = map[string]*Command{ "/use": { Args: []string{"ID"}, Description: "Uses a given item by ID", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(args) != 1 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid command "}, }) return } c.Player.Inventory.useById(args[0]) }, }, "/shopsell": { Args: []string{"merchantID", "inventoryIndex"}, Description: "Sells the item at the given inventory index to the given merchant(id)", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(args) < 2 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid command, try /shop <id> <inventory index>"}, }) return } buildingId := args[0] index, err := strconv.ParseInt(args[1], 10, 32) if err != nil { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid sell index."}, }) return } var building *Building for _, b := range c.Player.Loc.Buildings { if b.ID == buildingId { building = b } } if building == nil { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid building."}, }) return } item := c.Player.Inventory.Items[index] if item == nil { return } building.Mu.Lock() defer building.Mu.Unlock() amount, ok := building.ShopBuyType[item.GetItemType()] if !ok { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I am not interested in that..", }) return } if amount == 0 { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I am not looking to buy more of that type of item.", }) return } itemEvent := c.Player.Inventory.drop(int(index)) if itemEvent == nil { return } money := int64(float32(itemEvent.Item.GetPrice()) * settings.ItemSellPriceLoss) if money == 0 { money = 1 } c.Player.Mu.Lock() c.Player.Cash += money c.Player.Mu.Unlock() if amount != -1 { building.ShopBuyType[itemEvent.Item.GetItemType()] -= 1 } logger.LogBuySell(c.Player.Name, "sell", money, itemEvent.Item.TemplateName) building.SyncShopInventory(c) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_SUCCESS, Message: fmt.Sprintf("Here's $%d for the %s", money, itemEvent.Item.GetName()), }) }, }, "/shopbuy": { Args: []string{"shop type", "inventory index"}, Description: "Buys the item at the given inventory index from the given shop", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) < 2 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid command, try /shop <id> <inventory index>"}, }) return } buildingId := args[0] index, err := strconv.ParseInt(args[1], 10, 32) if err != nil { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid sell index."}, }) return } var building *Building for _, b := range c.Player.Loc.Buildings { if b.ID == buildingId { building = b } } if building == nil { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid building."}, }) return } if building.ShopStock == nil || len(building.ShopStock) <= 0 { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid shop."}, }) return } if index < 0 || int(index) >= len(building.ShopStock) { c.SendEvent(&responses.Generic{ Messages: []string{"Invalid index."}, }) return } itemToBuy := building.ShopStock[index] if itemToBuy.Amount == 0 { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I have none of those left, pick something else.", }) return } itemTemplate := ItemsList[itemToBuy.TemplateId] if itemTemplate.GetMinRep() > c.Player.Reputation { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I don't know you well enough to sell you that. Come back when your name is more known.", }) return } c.Player.Mu.Lock() defer c.Player.Mu.Unlock() if int64(itemTemplate.GetPrice()) > c.Player.Cash { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "You do not have enough money on you, come back when you have cash.", }) return } if !c.Player.Inventory.HasRoom() { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "You don't have enough room to buy that.", }) return } newItem, ok := NewItem(itemToBuy.TemplateId) if !ok { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I can't seem to find that item.. odd. Come back later (Error)", }) return } c.Player.Cash -= int64(itemTemplate.GetPrice()) err = c.Player.Inventory.addItem(newItem) if err != nil { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "You don't seem to have room, I've dropped the item on the ground (Inventory error)", }) c.Player.Loc.AddItem <- &ItemMoved{ Item: newItem, By: building.Name, } return } logger.LogBuySell(c.Player.Name, "buy", int64(itemTemplate.GetPrice()), itemTemplate.TemplateName) c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_SUCCESS, Message: fmt.Sprintf("Done. Here's your %s.", newItem.GetName()), }) building.SyncShopInventory(c) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() }, }, "/selldrug": { Args: []string{"merchant id", "inventory index"}, Description: "Sells the item at the given inventory index to the given merchant(id)", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player == nil { return } if len(args) < 2 { return } var druggie *Entity sellerID := args[0] index, err := strconv.ParseInt(args[1], 10, 32) if err != nil { return } for npc := range c.Player.ShoppingWith { if npc.NpcType == DrugAddict && sellerID == npc.NpcID { druggie = npc break } } if druggie == nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{"There is no one here to tell to."}, }) return } if isHostile := druggie.NpcHostiles[c.UUID]; isHostile { return } item := c.Player.Inventory.Items[index] if item == nil { return } if item.GetItemType() != ItemTypeDrug { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I am not interested in that..", }) return } if !druggie.Inventory.HasRoom() { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "I got what I need, go sell your shit to someone else.", }) return } itemEvent := c.Player.Inventory.drop(int(index)) if itemEvent == nil { return } price := int64((float32(itemEvent.Item.GetPrice()) * settings.DrugProfitMargin) * c.Player.Loc.City.DrugDemands[item.TemplateName]) if price <= 0 { price = 1 } c.Player.Mu.Lock() c.Player.Cash += price c.Player.Reputation += settings.DrugRepIncrease c.Player.Mu.Unlock() logger.LogBuySell(c.Player.Name, "sell", price, itemEvent.Item.TemplateName) druggie.Inventory.addItem(itemEvent.Item) druggie.SyncDruggieTrade(c) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_SUCCESS, Message: fmt.Sprintf("Here's $%d for the %s", price, itemEvent.Item.GetName()), }) }, }, "/purchase": { Args: []string{"merchant id", "inventory index"}, Description: "Buys the item at the given inventory index from the given merchant(id)", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player == nil { return } if len(args) < 2 { return } var dealer *Entity sellerID := args[0] index, err := strconv.ParseInt(args[1], 10, 32) if err != nil { return } for t := range c.Player.Loc.Npcs { if t.NpcType == DrugDealer && t.NpcID == sellerID { dealer = t break } } if isHostile := dealer.NpcHostiles[c.UUID]; isHostile { return } dealer.Inventory.Mu.Lock() c.Player.Inventory.Mu.Lock() defer dealer.Inventory.Mu.Unlock() defer c.Player.Inventory.Mu.Unlock() if !c.Player.Inventory.HasRoom() { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "There is no room left in your inventory.", }) return } item := dealer.Inventory.Items[index] if item == nil { return } c.Player.Mu.Lock() price := int64(float32(item.GetPrice()) * c.Player.Loc.City.DrugDemands[item.TemplateName]) if price <= 0 { price = 1 } if c.Player.Cash < price { c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Message: "You do not have enough cash for that.", }) c.Player.Mu.Unlock() return } logger.LogBuySell(c.Player.Name, "buy", price, item.TemplateName) c.Player.Mu.Unlock() go func() { c.Player.Mu.Lock() defer c.Player.Mu.Unlock() itemEvent := dealer.Inventory.drop(int(index)) if itemEvent == nil { return } c.Player.Cash -= price c.Player.Inventory.addItem(itemEvent.Item) dealer.SyncDealerInventory(c) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() c.SendEvent(&responses.MerchantMessage{ Status: responses.ResponseStatus_RESPONSE_STATUS_SUCCESS, Message: fmt.Sprintf("Here is your %s, anything else?", itemEvent.Item.GetName()), }) }() }, }, "/closetrade": { Args: []string{"name"}, Description: "close active trade", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player == nil { return } c.Player.Mu.Lock() for t := range c.Player.ShoppingWith { t.Mu.Lock() delete(t.ShoppingWith, c.Player) delete(c.Player.ShoppingWith, t) t.Mu.Unlock() } c.Player.Mu.Unlock() }, }, "/sell": { Args: []string{"name"}, Description: "Opens drug sellng menu", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player == nil { return } var druggie *Entity var altDruggie *Entity name := "" if len(args) > 0 { name = strings.ToLower(args[0]) } for t := range c.Player.Loc.Npcs { if t.NpcType == DrugAddict { altDruggie = t if strings.HasPrefix(strings.ToLower(t.Name), name) { druggie = t break } } } if druggie == nil { druggie = altDruggie if druggie == nil { c.SendEvent(&responses.Generic{ Messages: []string{"There are no druggies by that name."}, }) return } } druggie.OpenDruggieMenu(c) }, }, "/buy": { Args: []string{"name"}, Description: "Opens drug dealers buy menu", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player == nil { return } var dealer *Entity var altDealer *Entity name := "" if len(args) > 0 { name = strings.ToLower(args[0]) } for t := range c.Player.Loc.Npcs { if t.NpcType == DrugDealer { altDealer = t if strings.HasPrefix(strings.ToLower(t.Name), name) { dealer = t break } } } if dealer == nil { dealer = altDealer if dealer == nil { c.SendEvent(&responses.Generic{ Messages: []string{"There are no drug dealers here going by that name."}, }) return } } dealer.OpenDrugDealer(c) }, }, "/unequip": { Args: []string{"itemID"}, Description: "Unequips the given item", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(args) != 1 { return } index, err := strconv.ParseInt(args[0], 10, 32) if err != nil || index < 0 { return } c.Player.Inventory.unequip(int(index)) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() }, }, "/info": { Args: []string{"itemID"}, Description: "Gives info on the item", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(args) != 1 { return } ID := args[0] c.Player.Inventory.Info(ID) }, }, "/equip": { Args: []string{"itemID"}, Description: "Equips the given item", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(args) != 1 { return } ID := args[0] c.Player.Inventory.equip(ID) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() }, }, "/unaim": { Args: []string{}, Description: "Removes your target lock", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player.Loc == nil { return } if c.Player.CurrentTarget == nil { return } c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("You stop taking aim at %s", c.Player.CurrentTarget.Name)}, }) c.Player.CurrentTarget.Client.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("%s stops taking aim at you.", c.Player.Name)}, }) delete(c.Player.CurrentTarget.TargetedBy, c.Player) c.Player.CurrentTarget = nil }, }, "/aim": { Args: []string{"target"}, Description: "Sets your for your attacks. The target cannot move away while aim'ed at", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(args) == 0 { return } var target *Entity name := strings.ToLower(args[0]) for t := range c.Player.Loc.Players { if strings.HasPrefix(strings.ToLower(t.Player.Name), name) { target = t.Player break } } if target == nil { for t := range c.Player.Loc.Npcs { if strings.HasPrefix(strings.ToLower(t.Name), name) { target = t break } } } if target == nil { c.SendEvent(&responses.Generic{ Messages: []string{"There are no one here going by that name."}, }) return } action := CombatAction{ Target: target, Attacker: c.Player, Action: CombatActionAim, } action.Execute() }, }, "/punch": { Args: []string{}, Description: "Throws a punch at the target", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player.Loc == nil { return } if c.Player.CurrentTarget == nil { c.SendEvent(&responses.Generic{ Messages: []string{"You have no target, so you throw some punches into the air."}, }) return } action := CombatAction{ Target: c.Player.CurrentTarget, Attacker: c.Player, Action: CombatActionPunch, } action.Execute() }, }, "/strike": { Args: []string{}, Description: "Strikes the target with your melee weapon", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player.Loc == nil { return } if c.Player.CurrentTarget == nil { c.SendEvent(&responses.Generic{ Messages: []string{"You have no target."}, }) return } action := CombatAction{ Target: c.Player.CurrentTarget, Attacker: c.Player, Action: CombatActionStrike, } action.Execute() }, }, "/shoot": { Args: []string{}, Description: "Shoots at the target with your gun", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player.Loc == nil { return } if c.Player.CurrentTarget == nil { c.SendEvent(&responses.Generic{ Messages: []string{"You have no target."}, }) return } action := CombatAction{ Target: c.Player.CurrentTarget, Attacker: c.Player, Action: CombatActionShoot, } action.Execute() }, }, "/autoattack": { Args: []string{}, Description: "Will toggle auto attack on/off.", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { c.Player.Mu.Lock() c.Player.AutoAttackEnabled = !c.Player.AutoAttackEnabled c.Player.Mu.Unlock() c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{ "Auto Attack, when enabled, will attack an /aim'ed target with the last type of attack used (default: Punch)", fmt.Sprintf("Auto Attack enabled: %v", c.Player.AutoAttackEnabled), }, }) }, }, "/flee": { Args: []string{"direction"}, Description: "Run away from a fight, in the choosen direction, but you could drop some items in the process", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(c.Player.TargetedBy) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"No one is targeting you, no need to flee"}, }) return } north := c.Player.Loc.Coords.North east := c.Player.Loc.Coords.East switch strings.ToLower(args[0]) { case "up", "w", "north": north += 1 case "down", "s", "south": north += -1 case "left", "a", "west": east += -1 case "right", "d", "east": east += 1 } if north < 0 || north > int(c.Player.Loc.City.Height) || east < 0 || east > int(c.Player.Loc.City.Width) { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_WARN, Messages: []string{ "You cannot move any further in that direction that direction", }, }) return } action := CombatAction{ Target: c.Player, Action: CombatActionFlee, Direction: &Coordinates{ North: c.Player.Loc.Coords.North + north, East: c.Player.Loc.Coords.East + east, }, } action.Execute() }, }, "/pickup": { Args: []string{"itemid or name"}, Description: "Pickup item of a given name or specific id", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if c.Player.Loc == nil { return } if len(c.Player.Loc.Items) == 0 { c.SendEvent(&responses.Generic{ Messages: []string{"There are no items laying on the ground."}, }) return } var puItem *Item if len(args) > 0 { nameArg := strings.ToLower(args[0]) idArg := args[0] var itmById *Item var itmByName *Item for item := range c.Player.Loc.Items { if item.ID == idArg { itmById = item itmByName = nil break } if strings.HasPrefix(strings.ToLower(item.GetName()), nameArg) { itmByName = item break } } if itmById != nil { puItem = itmById } if itmByName != nil { puItem = itmByName } if puItem == nil { c.SendEvent(&responses.Generic{ Messages: []string{"There are no items on the ground beginning with that."}, }) return } } else { for item := range c.Player.Loc.Items { puItem = item break } } logger.LogItems(c.Player.Name, "pickup", puItem.TemplateName, c.Player.Loc.Coords.North, c.Player.Loc.Coords.East, c.Player.Loc.Coords.City) c.Player.Loc.RemoveItem <- &ItemMoved{ Item: puItem, By: c.Player.Name, Player: c.Player, } }, }, "/drop": { Args: []string{"inventory slot"}, Description: "Drop an item at a given inventory slot", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) == 0 { return } if c.Player.Loc == nil { return } slotIndex, err := strconv.ParseUint(args[0], 10, 32) if err != nil { fmt.Println(err.Error()) return } event := c.Player.Inventory.drop(int(slotIndex)) if event != nil { c.Player.Loc.AddItem <- event } logger.LogItems(c.Player.Name, "drop", event.Item.TemplateName, c.Player.Loc.Coords.North, c.Player.Loc.Coords.East, c.Player.Loc.Coords.City) }, }, "/npcs": { Args: []string{}, Description: "List of all NPCs.", AllowInGame: true, AllowUnAuthed: true, AllowAuthed: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { headings := []string{"Name", "health", "Accuracy", "Damage", "Armor (Range)", "Armor (Melee)"} data := [][]string{} for _, tmpl := range NpcTemplates { dmg := 2 drRange := 0 drMelee := 0 if tmpl.Equipment != nil { if gunId, ok := tmpl.Equipment[ItemTypeGun]; ok { gun := ItemsList[gunId] if gun != nil { dmg = int(gun.Damage) } if ammoId, ok := tmpl.Equipment[ItemTypeAmmo]; ok { ammo := ItemsList[ammoId] if ammo != nil { dmg += int(ammo.Damage) } } } if meleeId, ok := tmpl.Equipment[ItemTypeMelee]; ok { weapon := ItemsList[meleeId] if weapon != nil { dmg = int(weapon.Damage) } } if armorId, ok := tmpl.Equipment[ItemTypeArmor]; ok { armor := ItemsList[armorId] if armor != nil { drMelee = int(armor.ArmorGuns) drRange = int(armor.ArmorMelee) } } } data = append(data, []string{ tmpl.Title, fmt.Sprintf("%d", tmpl.Health), fmt.Sprintf("%.2f", tmpl.SkillAcc), fmt.Sprintf("%d", dmg), fmt.Sprintf("%d", drRange), fmt.Sprintf("%d", drMelee), }) } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, data), }) }, }, "/help": { Args: []string{}, Description: "List of all general commands and controls.", AllowInGame: true, AllowUnAuthed: true, AllowAuthed: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { c.SendEvent(&responses.Generic{ Ascii: true, Messages: []string{" ", " ", "Here is a list of all common commands:"}, }) headings := []string{"Command", "Description"} commands := [][]string{ {"/<command> help", "Most commands have a help menu, explaining its use."}, {"/here", "Will tell you what commands are available at a given location (if any)"}, {"/say", "Send a chat message visible only to those in the same location."}, {"/global", "Send a chat message visible to all online players."}, {"/pm <name> <msg>", "Send a private chat message to the specified player."}, {"/buy <name>", "Open drug dealer buy menu"}, {"/sell <name>", "Open drug addict sell menu"}, {"/shop", "Open the shop window (eg. arms dealer)"}, {"/aim <name>", "Takes aim at a target, required before you attack"}, {"/unaim", "Removes your lock on the target"}, {"/flee <dir>", "Escapes from battle, but you loose items."}, {"/autoattack", "Toggles auto-attack on/off."}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, commands), }) c.SendEvent(&responses.Generic{ Ascii: true, Messages: []string{" ", " ", "This is all the controls:"}, }) ctrlHeadings := []string{"Keyboard Key", "Alt. Key", "Description"} ctrls := [][]string{ {"W", "K, Arrow Up", "Move 1 space north"}, {"A", "H, Arrow Left", "Move 1 space West"}, {"S", "J, Arrow Down", "Move 1 space South"}, {"D", "L, Arrow Right", "Move 1 space East"}, {"R", "", "Clears event log, and gets the location latest changes"}, {"I", "Enter", "Focuses the command input if not already focused."}, {"Esc.", "", "Unfocuses the command input, if in focus"}, {"1", "", "Strike your target with your fist (2dmg)"}, {"2", "", "Strike your target with your melee weapon (weapon dmg)"}, {"3", "", "Shoot your target with you gun (weapon dmg)"}, } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(ctrlHeadings, ctrls), }) c.SendEvent(&responses.Generic{ Messages: []string{ "Deal drug to gain money and increase your reputation. The more reputation you have, the more things you can buy and do.", "This game is full-loot PvPvE, anything player or NPC carry will be dropped when killed, and any cash on them will go to the killer.", "", }, }) }, }, "/here": { Args: []string{}, Description: "Gives you information about available commands at a given location", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player.Loc == nil { return } if len(c.Player.Loc.Buildings) == 0 { return } headings := []string{"Command", "Description", "Example"} commands := [][]string{} for _, b := range c.Player.Loc.Buildings { for cmd, c := range b.Commands { commands = append(commands, []string{ cmd + " " + strings.Join(c.Args, " "), c.Description, c.Example, }) } } c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(headings, commands), }) }, }, "/pm": { Args: []string{"user", "message"}, Description: "Send a private message to a player", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) != 2 { return } playerName := args[0] message := strings.Join(args[1:], " ") var player *Entity for tc := range c.Game.Clients { if tc.Player == nil { return } if strings.ToLower(tc.Player.Name) == playerName { player = tc.Player break } } if player == nil { c.SendEvent(&responses.Generic{ Messages: []string{"There are no one online going by that name."}, }) return } logger.LogChat("private", c.Player.Name, message, player.Name) msg := []byte(message) msg = bytes.TrimSpace(bytes.ReplaceAll(msg, []byte{'\n'}, []byte{' '})) player.Client.SendEvent(&responses.Chat{ Type: responses.ChatType_CHAT_TYPE_PRIVATE, Player: c.Player.PlayerGameFrame(), Msg: string(msg), }) }, }, "/say": { Args: []string{"message"}, Description: "Send a message locally", AllowInGame: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) == 0 { return } if c.Player.Loc == nil { return } message := strings.Join(args, " ") logger.LogChat("local", c.Player.Name, message, "") msg := []byte(message) msg = bytes.TrimSpace(bytes.ReplaceAll(msg, []byte{'\n'}, []byte{' '})) event := responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{ fmt.Sprintf("(Local) %s: %s", c.Player.Name, string(msg)), }, } c.Player.Loc.Events <- &ClientResponse{ Payload: &event, } }, }, "/global": { Args: []string{"message"}, Description: "Send a message to the global chat.", AllowInGame: true, AllowAuthed: false, AllowUnAuthed: false, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) == 0 { return } message := strings.Join(args, " ") logger.LogChat("global", c.Player.Name, message, "") msg := []byte(message) msg = bytes.TrimSpace(bytes.ReplaceAll(msg, []byte{'\n'}, []byte{' '})) event := responses.Chat{ Type: responses.ChatType_CHAT_TYPE_GLOBAL, Player: c.Player.PlayerGameFrame(), Msg: string(msg), } c.Game.GlobalEvents <- &event }, }, "/refresh": { Args: []string{}, Description: "Refresh the game frame", AllowInGame: true, AllowAuthed: false, AllowUnAuthed: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { if c.Player == nil { c.Game.SendMOTD(c) return } c.Player.sendGameFrame(true) }, }, "/move": { Args: []string{"direction"}, Description: "Move in a provided direction.", AllowInGame: true, AllowAuthed: false, AllowUnAuthed: false, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) == 0 { return } if c.Player.Loc == nil { return } if len(c.Player.TargetedBy) > 0 { names := []string{} for p := range c.Player.TargetedBy { names = append(names, p.Name) } c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ fmt.Sprintf("You cannot move while being held up by: %s", strings.Join(names, ",")), "You can flee the area using: \"/flee <direction>\", eg \"/free north\", but you will drop some items.", }, }) return } now := time.Now().UnixMilli() if c.Player.LastMove+settings.PlayerMoveDelayMs > now { return } c.Player.LastMove = now north := c.Player.Loc.Coords.North east := c.Player.Loc.Coords.East switch strings.ToLower(args[0]) { case "up", "w", "north": north += 1 case "down", "s", "south": north += -1 case "left", "a", "west": east += -1 case "right", "d", "east": east += 1 } if north < 0 || north > int(c.Player.Loc.City.Height) || east < 0 || east > int(c.Player.Loc.City.Width) { c.SendEvent(&responses.Generic{ Messages: []string{ "You cannot go any further in that direction", }, }) return } newLocation := Coordinates{ North: int(north), East: int(east), } if val, ok := c.Player.Loc.City.Grid[newLocation.toString()]; ok { val.PlayerJoin <- c } }, }, "/new": { Args: []string{"name", "city"}, Description: "Creates a new character", AllowInGame: false, AllowAuthed: true, AllowUnAuthed: false, Help: func(c *Client) { }, Call: func(c *Client, args []string) { _, _, err := c.Game.GetUserCharacter(c.UserId) if err == nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "You cannot crate a character. You are not logged in", }, }) return } if len(args) < 2 { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Invalid command. The format is: \"/login username password\"", }, }) return } name := args[0] city := args[1] if _, ok := c.Game.World[city]; !ok { list := []string{} for c := range c.Game.World { list = append(list, c) } c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Invalid City. Your options are:", strings.Join(list, ", "), }, }) return } row := c.Game.DbConn.QueryRow("SELECT id FROM characters WHERE LOWER(name) = ?", strings.ToLower(name)) char := models.Character{} row.Scan(&char.Id) if char.Id != 0 { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "That name is already taken.", }, }) return } hometown := c.Game.World[city] startLocation := hometown.RandomLocation() newChar := models.Character{ UserId: c.UserId, Name: name, Cash: settings.PlayerStartCash, Reputation: settings.PlayerStartReputation, Bank: settings.PlayerStartBank, Health: settings.PlayerMaxHealth, SkillAcc: settings.PlayerStartSkillAcc, SkillTrack: settings.PlayerStartSkillTrack, SkillHide: settings.PlayerStartSkillHide, SkillSnoop: settings.PlayerStartSkillSnoop, SkillSearch: settings.PlayerStartSkillSearch, Hometown: hometown.ShortName, LocationNorth: startLocation.North, LocationEast: startLocation.East, LocationCity: hometown.ShortName, CreatedAt: time.Now().Unix(), } result, err := c.Game.DbConn.Exec( "INSERT INTO characters (user_id, name, reputation, health, npc_kill, player_kills, cash, bank, hometown, skill_acc, skill_track, skill_hide, skill_snoop, skill_search, location_n, location_e, location_city, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", &newChar.UserId, &newChar.Name, &newChar.Reputation, &newChar.Health, 0, 0, &newChar.Cash, &newChar.Bank, &newChar.Hometown, &newChar.SkillAcc, &newChar.SkillTrack, &newChar.SkillHide, &newChar.SkillSnoop, &newChar.SkillSearch, &newChar.LocationNorth, &newChar.LocationEast, &newChar.LocationCity, &newChar.CreatedAt, ) if err != nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Failed to create character, system error.", }, }) return } lastId, err := result.LastInsertId() if err != nil { log.Print(err) c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Failed to create character, system error.", }, }) return } newChar.Id = uint64(lastId) player, lastLocation, err := c.Game.GetUserCharacter(newChar.UserId) if err != nil { log.Print(err) c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Failed load in your character, system error.", }, }) return } c.Game.LoginPlayer(c, player, lastLocation) }, }, "/authenticate": { Args: []string{"username", "password"}, Description: "Login to your account.", AllowInGame: false, AllowAuthed: false, AllowUnAuthed: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) < 2 { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Invalid command. The format is: \"/login username password\"", }, }) return } email := args[0] password := args[1] row := c.Game.DbConn.QueryRow("SELECT id, password, user_type FROM users WHERE email = ? LIMIT 1", email) if row == nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Invalid username and password combination.", }, }) return } user := models.User{} err := row.Scan(&user.Id, &user.Password, &user.UserType) if user.Id == 0 || err != nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Invalid username and password combination.", }, }) return } if ok, err := internal.CheckPassword(password, user.Password); !ok || err != nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_ERROR, Messages: []string{ "Invalid username and password combination.", }, }) return } c.Authenticated = true c.UserId = user.Id c.UserType = uint8(user.UserType) player, lastLocation, err := c.Game.GetUserCharacter(user.Id) if err != nil { c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_SUCCESS, Messages: []string{ "Your have been logged in, however you do not have a character yet.", "To create a new character type /new", }, }) return } c.Game.LoginPlayer(c, player, lastLocation) }, }, "/demand": { Args: []string{}, Description: "update drug demand for the city", AllowInGame: true, AdminCommand: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { c.Player.Loc.City.UpdateDrugDemand() }, }, "/save": { Args: []string{}, Description: "Save all online players", AllowInGame: true, AdminCommand: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { c.Game.Save() }, }, "/restock": { Args: []string{}, Description: "Restocks all drugs on the server", AllowInGame: true, AdminCommand: true, Help: func(c *Client) { }, Call: func(c *Client, _ []string) { c.Game.Restock() }, }, "/additem": { Args: []string{"itemid"}, Description: "Spawn a new item", AllowInGame: true, AdminCommand: true, Help: func(c *Client) { }, Call: func(c *Client, args []string) { if len(args) == 0 { return } if c.Player.Loc == nil { return } item, ok := NewItem(args[0]) if !ok { return } c.Player.Loc.AddItem <- &ItemMoved{ Item: item, By: c.Player.Name, } }, }, }
View Source
var FemaleNames = []string{}/* 300 elements not displayed */
View Source
var ItemTemplates = map[string]ItemTemplate{ "crack": { Name: "Crack", Description: "1 Gram", ItemType: ItemTypeDrug, BasePrice: 30, MaxPrice: 60, UseEffect: "usedrug", }, "coke": { Name: "Cocaine", Description: "1 Gram", ItemType: ItemTypeDrug, BasePrice: 60, MaxPrice: 100, UseEffect: "usedrug", }, "heroine": { Name: "Heroin", Description: "1 Gram", ItemType: ItemTypeDrug, BasePrice: 150, MaxPrice: 500, UseEffect: "usedrug", }, "meth": { Name: "Meth", Description: "1 Gram", ItemType: ItemTypeDrug, BasePrice: 20, MaxPrice: 40, UseEffect: "usedrug", }, "weed": { Name: "Weed", Description: "7 Grams / a quater ounce", ItemType: ItemTypeDrug, BasePrice: 25, MaxPrice: 50, UseEffect: "usedrug", }, "fentanyl": { Name: "Fentanyl", Description: "1 Pill", ItemType: ItemTypeDrug, BasePrice: 25, MaxPrice: 50, UseEffect: "usedrug", }, "pcp": { Name: "PCP", Description: "1 tablet", ItemType: ItemTypeDrug, BasePrice: 5, MaxPrice: 15, UseEffect: "usedrug", }, "ketamine": { Name: "Ketamine", Description: "A dose", ItemType: ItemTypeDrug, BasePrice: 20, MaxPrice: 30, UseEffect: "usedrug", }, "iia_armor": { Name: "Level IIA Body Armor", Description: "Designed to protect against 9mm.", ItemType: ItemTypeArmor, BasePrice: 300, ArmorGuns: 3, MinRep: RanksList[6].MinRep, }, "ii_armor": { Name: "Level II Body Armor", Description: "Provides protection against upto .357 Magnum.", ItemType: ItemTypeArmor, BasePrice: 700, ArmorGuns: 7, MinRep: RanksList[10].MinRep, }, "iiia_armor": { Name: "Level IIIA Body Armor", Description: "Designed to protect against handgun threats, including .44 Magnum.", ItemType: ItemTypeArmor, BasePrice: 1100, ArmorGuns: 11, MinRep: RanksList[14].MinRep, }, "iii_armor": { Name: "Level III Body Armor", Description: "Designed to protect against rifle threats, including 7.62x51mm (M80) ball.", ItemType: ItemTypeArmor, BasePrice: 1500, ArmorGuns: 15, MinRep: RanksList[18].MinRep, }, "iv_armor": { Name: "Level IV Body Armor", Description: "Provides protection against armor-piercing rifle rounds, such as .30-06 M2 AP.", ItemType: ItemTypeArmor, BasePrice: 1900, ArmorGuns: 19, MinRep: RanksList[22].MinRep, }, "beretta92": { Name: "Beretta 92", Description: "A widely used semi-automatic pistol in 9mm, known for its accuracy and reliability.", ItemType: ItemTypeGun, BasePrice: 300, Damage: 3, MinRep: RanksList[5].MinRep, }, "glock22": { Name: "Glock 22", Description: "A popular law enforcement pistol chambered in .40 S&W, favored for its versatility.", ItemType: ItemTypeGun, BasePrice: 500, Damage: 5, MinRep: RanksList[7].MinRep, }, "sigp320": { Name: "Sig Sauer P220", Description: "The P220 is known for its reliability and is a favorite among enthusiasts. Chambered in 10mm", ItemType: ItemTypeGun, BasePrice: 700, Damage: 7, MinRep: RanksList[9].MinRep, }, "sw610": { Name: "Smith & Wesson Model 610", Description: "A versatile and durable stainless steel semi-automatic revolver chambered for .357 Magnum.", ItemType: ItemTypeGun, BasePrice: 900, Damage: 9, MinRep: RanksList[11].MinRep, }, "1911": { Name: "Colt 1911", Description: "One of the most iconic handguns in the world. Chambered in .45 ACP", ItemType: ItemTypeGun, BasePrice: 1100, Damage: 11, MinRep: RanksList[13].MinRep, }, "ragingbull": { Name: "Taurus Raging Bull", Description: "A large-framed revolver recognized for its power and ruggedness. Chambered in .44 Magnum.", ItemType: ItemTypeGun, BasePrice: 1300, Damage: 13, MinRep: RanksList[15].MinRep, }, "ar-15": { Name: "AR-15 Rifle", Description: "The AR-15 is a widely used semi-automatic rifle known for its modularity and adaptability. Chambered in 5.56x45mm NATO", ItemType: ItemTypeGun, BasePrice: 1500, Damage: 15, MinRep: RanksList[17].MinRep, }, "ak47": { Name: "AK-47", Description: "The AK-47 is a legendary and rugged assault rifle known for its reliability. Chambered in 7.62x39mm", ItemType: ItemTypeGun, BasePrice: 1700, Damage: 17, MinRep: RanksList[19].MinRep, }, "scarh": { Name: "FN SCAR-H", Description: "A versatile battle rifle used by military forces around the world. Chambered in 7.62x51mm NATO", ItemType: ItemTypeGun, BasePrice: 1900, Damage: 19, MinRep: RanksList[21].MinRep, }, "m82": { Name: "Barrett M82", Description: "The Barrett M82 is a renowned anti-materiel rifle chambered in .50 BMG.", ItemType: ItemTypeGun, BasePrice: 2100, Damage: 21, MinRep: RanksList[23].MinRep, }, "subsonic": { Name: "Subsonic Ammo", Description: "Subsonic rounds are typically lower in power due to their reduced velocity, making them quieter.", ItemType: ItemTypeAmmo, BasePrice: 100, Damage: 1, AmmoWear: 0.0025, MinRep: RanksList[5].MinRep, Amount: 15, }, "sdammo": { Name: "Standard Ammo", Description: "Standard ammunition, often referred to as \"ball\" ammunition, is the baseline cartridge for a particular caliber.", ItemType: ItemTypeAmmo, BasePrice: 300, Damage: 3, AmmoWear: 0.0040, MinRep: RanksList[9].MinRep, Amount: 15, }, "plusp": { Name: "+P Ammo", Description: "Cartridges labeled as +P are loaded with higher powder charges than standard loads of the same caliber.", ItemType: ItemTypeAmmo, BasePrice: 500, Damage: 5, AmmoWear: 0.0055, MinRep: RanksList[13].MinRep, Amount: 15, }, "pluspplus": { Name: "+P+ Ammo", Description: "These cartridges are loaded with significantly more powder, further increasing muzzle velocity and energy.", ItemType: ItemTypeAmmo, BasePrice: 700, Damage: 7, AmmoWear: 0.0070, MinRep: RanksList[17].MinRep, Amount: 15, }, "apammo": { Name: "AP Ammo", Description: "These cartridges are loaded with significantly more powder, further increasing muzzle velocity and energy.", ItemType: ItemTypeAmmo, BasePrice: 900, Damage: 9, AmmoWear: 0.0085, MinRep: RanksList[21].MinRep, Amount: 15, }, "brassknuckle": { Name: "Brass Knuckle", Description: "Brass knuckles, a classic street weapon, provide a discreet and formidable edge in close combat.", ItemType: ItemTypeMelee, BasePrice: 300, Damage: 3, MinRep: RanksList[6].MinRep, }, "pipewrench": { Name: "Pipe Wrench", Description: "A heavy-duty pipe wrench, perfect for tight spaces and DIY repairs. A symbol of blue-collar craftsmanship.", ItemType: ItemTypeMelee, BasePrice: 500, Damage: 5, MinRep: RanksList[8].MinRep, }, "crowbar": { Name: "Crowbar", Description: "A versatile tool and makeshift weapon, the crowbar can pry open doors, crates, and skulls with equal efficiency.", ItemType: ItemTypeMelee, BasePrice: 700, Damage: 7, MinRep: RanksList[10].MinRep, }, "switchblade": { Name: "Switchblade", Description: "The switchblade, a compact folding knife, offers quick and discreet access for self-defense or utility in a pinch.", ItemType: ItemTypeMelee, BasePrice: 900, Damage: 9, MinRep: RanksList[12].MinRep, }, "bbbat": { Name: "Baseball Bat", Description: "A solid baseball bat, ideal for both sports and as an improvised weapon. Swing for the fences or fend off threats.", ItemType: ItemTypeMelee, BasePrice: 1100, Damage: 11, MinRep: RanksList[14].MinRep, }, "fireaxe": { Name: "Fire Axe", Description: "A heavy-duty fire axe, designed for breaking through obstacles and providing a powerful, life-saving tool in emergencies.", ItemType: ItemTypeMelee, BasePrice: 1300, Damage: 13, MinRep: RanksList[16].MinRep, }, "machete": { Name: "Machete", Description: "The machete, a rugged cutting tool, is essential for clearing foliage or defending against the wild and unexpected.", ItemType: ItemTypeMelee, BasePrice: 1500, Damage: 15, MinRep: RanksList[18].MinRep, }, "katana": { Name: "Katana", Description: "The katana, a legendary Japanese sword, balances precision and power, making it a deadly choice for any skilled warrior.", ItemType: ItemTypeMelee, BasePrice: 1700, Damage: 17, MinRep: RanksList[20].MinRep, }, "chainsaw": { Name: "Chainsaw", Description: "A fearsome chainsaw, designed for heavy-duty cutting and capable of unleashing raw, mechanical power in the right hands.", ItemType: ItemTypeMelee, BasePrice: 1900, Damage: 19, MinRep: RanksList[22].MinRep, }, "stabvest": { Name: "Stab-Resistant Vest", Description: "Made of materials such as Kevlar and laminated fabrics. Designed to resist punctures from knives and other sharp-edged weapons.", ItemType: ItemTypeArmor, BasePrice: 400, ArmorMelee: 4, MinRep: RanksList[10].MinRep, }, "chainmail": { Name: "Chainmail", Description: "Modern chainmail is made from materials like steel or titanium rings. It provides good protection against slashing attacks from knives and swords.", ItemType: ItemTypeArmor, BasePrice: 700, ArmorMelee: 7, MinRep: RanksList[14].MinRep, }, "hardarmor": { Name: "Hard Plate Armor", Description: "Usually made from ceramics, steel, or composite materials. They provide excellent protection against knife and sword strikes", ItemType: ItemTypeArmor, BasePrice: 1000, ArmorMelee: 10, MinRep: RanksList[18].MinRep, }, "smartphone": { Name: "Smart Phone", Description: fmt.Sprintf("Use the get the location of druggies and dealer, for the small fee of $%d to your informant of cause.", settings.SmartPhoneCost), ItemType: ItemTypeSmartPhone, BasePrice: 350, UseEffect: "smartphone", }, "deserteagle": { Name: "Desert Eagle", Description: "The Desert Eagle .50 AE is a semi-automatic handgun that stands out for its considerable size and firepower. Chambered in .50 AE", ItemType: ItemTypeGun, BasePrice: 500, Damage: 15, }, "brokenbottle": { Name: "Broken Bottle", Description: "A broken bottle that has been damaged, resulting in sharp and jagged edges.", ItemType: ItemTypeMelee, BasePrice: 50, Damage: 2, }, "guitar": { Name: "Guitar", Description: "A six-stringed musical instrument known for its versatility and soulful melodies.", ItemType: ItemTypeMelee, BasePrice: 100, Damage: 4, }, "leadpipe": { Name: "Lead Pipe", Description: "A heavy and sturdy cylindrical tube typically made of lead or other dense materials.", ItemType: ItemTypeMelee, BasePrice: 100, Damage: 4, }, "parcel": { Name: "Parcel", Description: "A securely wrapped package or envelope intended for delivery or transport.", ItemType: ItemTypeMelee, BasePrice: 50, Damage: 2, }, "mac-10": { Name: "MAC-10", Description: "\"Military Armament Corporation Model 10\" is a compact, blowback-operated submachine gun. Chambered in .45 ACP", ItemType: ItemTypeGun, BasePrice: 400, Damage: 11, }, "bikelock": { Name: "Bike Lock", Description: "In the hands of a resourceful individual, it becomes an improvised weapon, offering reach and a blunt force impact", ItemType: ItemTypeMelee, BasePrice: 75, Damage: 3, }, "goldchain": { Name: "Gold Chain", Description: "A accessory made of linked gold segments.", ItemType: ItemTypeTrash, BasePrice: 300, }, "festivalticket": { Name: "Festival Ticket", Description: "A ticket for music festival", ItemType: ItemTypeTrash, BasePrice: 150, }, "sunglasses": { Name: "Sun Glasses", Description: "Old, but decent brand.", ItemType: ItemTypeTrash, BasePrice: 100, }, "deliverypackage": { Name: "\"Amazone\" Package", Description: "Something is inside.", ItemType: ItemTypeTrash, BasePrice: 100, }, "currentthing": { Name: "Current Thing", Description: "An item which shows you support the \"Current Thing\".", ItemType: ItemTypeTrash, BasePrice: 100, }, "policebadge": { Name: "Police Badge", Description: "Standard police badge.", ItemType: ItemTypeTrash, BasePrice: 300, }, }
View Source
var MaleNames = []string{}/* 300 elements not displayed */
View Source
var NpcTemplates = map[NPCType]NpcTemplate{ DrugDealer: { NpcType: DrugDealer, Title: "Drug Dealer", Health: 500, Cash: 1000, Rep: -1750, SkillAcc: 75.0, Gender: GenderMale, Equipment: map[IType]string{ ItemTypeArmor: "iiia_armor", ItemTypeGun: "deserteagle", ItemTypeAmmo: "plusp", }, }, DrugAddict: { NpcType: DrugAddict, Title: "Drug Addict", Gender: GenderRandom, Health: 300, Cash: 500, Rep: -1750, SkillAcc: 75.0, Equipment: map[IType]string{ ItemTypeArmor: "iiia_armor", ItemTypeGun: "ragingbull", ItemTypeAmmo: "plusp", }, }, Homeless: { NpcType: Homeless, Title: "Homeless", Gender: GenderRandom, Health: 80, Cash: 12, Rep: 25, SkillAcc: 15.0, Inventory: []string{ "crack", "ketamine", }, Equipment: map[IType]string{ ItemTypeMelee: "brokenbottle", }, }, Tweaker: { NpcType: Tweaker, Title: "Tweaker", Gender: GenderRandom, Health: 100, Cash: 25, Rep: 140, SkillAcc: 35.0, Inventory: []string{ "meth", "meth", }, Equipment: map[IType]string{ ItemTypeMelee: "crowbar", }, }, Bouncer: { NpcType: Bouncer, Title: "Bouncer", Gender: GenderRandom, Health: 110, Cash: 200, SkillAcc: 45.0, Rep: 272, Inventory: []string{ "coke", "goldchain", }, Equipment: map[IType]string{ ItemTypeMelee: "bbat", ItemTypeArmor: "stabvest", }, }, Busker: { NpcType: Busker, Title: "Busker", Gender: GenderRandom, Health: 100, Cash: 70, SkillAcc: 35, Rep: 70, Inventory: []string{ "festivalticket", "weed", }, Equipment: map[IType]string{ ItemTypeMelee: "guitar", }, }, StreetVendor: { NpcType: StreetVendor, Title: "Street Vendor", Gender: GenderRandom, Health: 140, Cash: 80, SkillAcc: 40, Rep: 70, Inventory: []string{ "sunglasses", }, Equipment: map[IType]string{ ItemTypeMelee: "leadpipe", }, }, DeliveryDriver: { NpcType: DeliveryDriver, Title: "Delivery Driver", Gender: GenderRandom, Health: 100, Cash: 10, SkillAcc: 40, Rep: 80, Inventory: []string{ "deliverypackage", "smartphone", }, Equipment: map[IType]string{ ItemTypeMelee: "parcel", }, }, Tourist: { NpcType: Tourist, Title: "Tourist", Gender: GenderRandom, Health: 65, Cash: 10, SkillAcc: 25, Rep: 33, Inventory: []string{ "smartphone", "sunglasses", }, Equipment: map[IType]string{}, }, StreetGangMember: { NpcType: StreetGangMember, Title: "Street Gang Member", Gender: GenderRandom, Health: 150, Cash: 400, SkillAcc: 50, Rep: 412, Inventory: []string{ "sdammo", "sdammo", "sdammo", "coke", "coke", "weed", }, Equipment: map[IType]string{ ItemTypeGun: "mac-10", ItemTypeAmmo: "sdammo", ItemTypeArmor: "ii_armor", }, }, Activist: { NpcType: Activist, Title: "Activist", Gender: GenderRandom, Health: 40, Cash: 20, SkillAcc: 10, Rep: 20, Inventory: []string{ "currentthing", "weed", }, Equipment: map[IType]string{ ItemTypeMelee: "bikelock", }, }, BeatCop: { NpcType: BeatCop, Title: "Beat Cop", Gender: GenderRandom, Health: 100, Cash: 30, SkillAcc: 50, Rep: 200, Inventory: []string{ "policebadge", "sdammo", "sdammo", }, Equipment: map[IType]string{ ItemTypeGun: "glock22", ItemTypeAmmo: "sdammo", ItemTypeArmor: "iia_armor", }, }, PoliceOfficer: { NpcType: PoliceOfficer, Title: "Police Officer", Gender: GenderRandom, Health: 130, Cash: 30, SkillAcc: 60, Rep: 546, Inventory: []string{ "policebadge", "sdammo", "sdammo", }, Equipment: map[IType]string{ ItemTypeGun: "1911", ItemTypeAmmo: "sdammo", ItemTypeArmor: "ii_armor", }, }, }
View Source
var RanksList = [...]*Rank{
{Name: "Crackhead", MinRep: -1400},
{Name: "Street Trash", MinRep: -400},
{Name: "Disrespectable Punk", MinRep: -100},
{Name: "Nobody", MinRep: 0},
{Name: "Wannabe", MinRep: 100},
{Name: "Slacker", MinRep: 400},
{Name: "Street Punk", MinRep: 1400},
{Name: "Thug Wannabe", MinRep: 3400},
{Name: "Thug", MinRep: 7000},
{Name: "Hustler", MinRep: 12500},
{Name: "Wanskta", MinRep: 20500},
{Name: "Gangster", MinRep: 31700},
{Name: "Soldier", MinRep: 46600},
{Name: "Playa", MinRep: 65900},
{Name: "Pimp", MinRep: 90500},
{Name: "Pusher", MinRep: 120900},
{Name: "Smuggler", MinRep: 158100},
{Name: "Gun Runner", MinRep: 203000},
{Name: "Mobster", MinRep: 256500},
{Name: "Drug Lord", MinRep: 319400},
{Name: "Capo", MinRep: 393000},
{Name: "Underboss", MinRep: 478200},
{Name: "Don", MinRep: 576100},
{Name: "Kingpin", MinRep: 688000},
}
View Source
var UseEffectsList = map[string]*ItemUseEffect{ "smartphone": { Use: func(c *Client, _ *Item, _ int) { if c.Player.Loc == nil { return } c.Player.Mu.Lock() defer c.Player.Mu.Unlock() var useCost int64 = settings.SmartPhoneCost if c.Player.Bank < useCost { c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("This information does not come for free, you don't have the $%d it costs in your bank.", useCost)}, }) } c.Player.Bank -= useCost ctrlHeadings := []string{"Who", "Last Known Location"} locations := [][]string{} for npc := range c.Player.Loc.City.NPCs[DrugDealer] { if npc.Loc == nil { continue } locations = append(locations, []string{ fmt.Sprintf("%s the %s", npc.Name, npc.NpcTitle), fmt.Sprintf("N%d-E%d", npc.Loc.Coords.North, npc.Loc.Coords.East), }) } for npc := range c.Player.Loc.City.NPCs[DrugAddict] { if npc.Loc == nil { continue } locations = append(locations, []string{ fmt.Sprintf("%s the %s", npc.Name, npc.NpcTitle), fmt.Sprintf("N%d-E%d", npc.Loc.Coords.North, npc.Loc.Coords.East), }) } c.SendEvent(&responses.Generic{ Status: responses.ResponseStatus_RESPONSE_STATUS_INFO, Messages: []string{fmt.Sprintf("Informant: \"(Phone) Your $%d was received. Alright, here is what I know..\"", useCost)}, }) c.SendEvent(&responses.Generic{ Ascii: true, Messages: internal.ToTable(ctrlHeadings, locations), }) c.Player.PlayerSendStatsUpdate() }, }, "usedrug": { Use: func(c *Client, item *Item, slotIndex int) { c.Player.Mu.Lock() c.Player.Inventory.Mu.Lock() healthCost := settings.DrugUseHealthCost var repGain int64 = settings.DrugUseRepGain if c.Player.Health <= healthCost { c.SendEvent(&responses.Generic{ Messages: []string{"Using this would kill you.."}, }) c.Player.Mu.Unlock() c.Player.Inventory.Mu.Unlock() return } c.Player.Health -= healthCost c.Player.Reputation += repGain c.Player.Mu.Unlock() item.Amount -= 1 c.Player.Inventory.Mu.Unlock() if item.Amount <= 0 { c.Player.Inventory.drop(slotIndex) } c.SendEvent(&responses.Generic{ Messages: []string{fmt.Sprintf("You use the %s. It didn't do your health any favours. (-%d Health, +%d Rep)", item.GetName(), healthCost, repGain)}, }) c.Player.PlayerSendInventoryUpdate() c.Player.PlayerSendStatsUpdate() }, }, }
Functions ¶
func CharacterToPlayer ¶
func CharacterToPlayer(c *models.Character) (*Entity, *Coordinates, error)
func ExecuteCommand ¶
func GenerateCities ¶
func GenerateItemsList ¶
func GenerateItemsList()
func HandleWsClient ¶
func HandleWsClient(g *Game, w http.ResponseWriter, r *http.Request)
Types ¶
type ActionType ¶
type ActionType uint8
type Building ¶
type Building struct { ID string Name string Description string BuildingType BuildingType MerchantType responses.MerchantType Commands map[string]*Command ShopStock []*StockItem ShopBuyType map[IType]int32 Mu sync.Mutex }
func NewBuilding ¶
func NewBuilding(t BuildingType) Building
func (*Building) SyncShopInventory ¶
type BuildingGameFrame ¶
type BuildingLocation ¶
type BuildingLocation struct { Coords Coordinates Buildings []BuildingType }
type BuildingTemplate ¶
type BuildingType ¶
type BuildingType = uint8
const ( BuildingTypeAirport BuildingType = 1 BuildingTypeHospital BuildingType = 2 BuildingTypeBank BuildingType = 3 BuildingTypeBar BuildingType = 4 BuildingTypeArms BuildingType = 5 BuildingTypePawnShop BuildingType = 6 )
type CheckNameBody ¶
type CheckNameBody struct {
Name string
}
type CheckNameResponse ¶
type City ¶
type City struct { Name string ShortName string ISO string Grid map[string]*Location Width uint Height uint TravelCostMin int64 TravelCostMax int64 TravelCost int64 Players map[*Client]bool PlayerJoin chan *Client PlayerLeave chan *Client CityEvents chan bool Game *Game NPCs map[NPCType]map[*Entity]bool NpcSpawnList map[NPCType]uint8 BuildingLocations []BuildingLocation POILocations []Coordinates DrugDemands map[string]float32 Mu sync.Mutex }
func NewCity ¶
func NewCity(templ *CityTemplate) *City
k = city/urban size in km2 size = round(sqrt(k)) * 2
func (*City) GeneratePOIs ¶
func (c *City) GeneratePOIs()
func (*City) RandomLocation ¶
func (c *City) RandomLocation() Coordinates
func (*City) RandomiseTravelCost ¶
func (c *City) RandomiseTravelCost()
func (*City) StartCityTimers ¶
func (c *City) StartCityTimers()
func (*City) UpdateDrugDemand ¶
func (c *City) UpdateDrugDemand()
type CityTemplate ¶
type Client ¶
type Client struct { Game *Game Player *Entity Authenticated bool UserId uint64 UUID string UserType uint8 CombatLogging bool Connection *websocket.Conn Send chan protoreflect.ProtoMessage Mu sync.Mutex }
func (*Client) SendEvent ¶
func (c *Client) SendEvent(msg protoreflect.ProtoMessage)
type ClientResponse ¶
type ClientResponse struct { Payload protoreflect.ProtoMessage Ignore map[uint64]bool }
func CreateEvent ¶
func CreateEvent(p map[uint64]bool, d protoreflect.ProtoMessage) ClientResponse
type CombatAction ¶
type CombatAction struct { Attacker *Entity Target *Entity Action ActionType Direction *Coordinates Success bool }
func (*CombatAction) Execute ¶
func (c *CombatAction) Execute()
func (*CombatAction) SameLocation ¶
func (c *CombatAction) SameLocation() bool
type Coordinates ¶
type Coordinates struct { North int `json:"north"` East int `json:"east"` City string `json:"city,omitempty"` POI string `json:"poi,omitempty"` POIType uint8 `json:"poitype,omitempty"` }
func (*Coordinates) SameAs ¶
func (c *Coordinates) SameAs(c2 *Coordinates) bool
type Entity ¶
type Entity struct { // Shared ----- Mu sync.Mutex Loc *Location CurrentTarget *Entity TargetedBy map[*Entity]bool Inventory *Inventory Name string Cash int64 Health int Dead bool SkillAcc skills.Accuracy IsPlayer bool LastLocation Coordinates // Player ----- PlayerID uint64 Bank int64 Gang *Gang Hometown string LastMove int64 LastSkill map[string]int64 LastAttack int64 PlayerKills uint NpcKills uint Reputation int64 UserId uint64 Rank *Rank Client *Client IsAdmin bool AutoAttackEnabled bool AutoAttackType ActionType SkillHide skills.Hide SkillSearch skills.Search SkillSnoop skills.Snoop SkillTrack skills.Track // NPC ----- NpcID string NpcCashReward int64 NpcGender Gender NpcType NPCType NpcTitle string NpcRepReward int32 NpcCommands map[string]*Command NpcHostiles map[string]bool // Shopping ----- ShoppingWith map[*Entity]int64 }
func (*Entity) ClearStock ¶
func (n *Entity) ClearStock()
func (*Entity) NPCFindTarget ¶
func (*Entity) NPCGameFrame ¶
func (*Entity) NPCStartRoutines ¶
func (n *Entity) NPCStartRoutines()
func (*Entity) OpenDrugDealer ¶
func (*Entity) OpenDruggieMenu ¶
func (*Entity) PlayerGameFrame ¶
func (*Entity) PlayerGetBuildingCommand ¶
func (*Entity) PlayerSendInventoryUpdate ¶
func (p *Entity) PlayerSendInventoryUpdate()
func (*Entity) PlayerSendLocationUpdate ¶
func (p *Entity) PlayerSendLocationUpdate()
func (*Entity) PlayerSendMapUpdate ¶
func (p *Entity) PlayerSendMapUpdate()
func (*Entity) PlayerSendPlayerList ¶
func (p *Entity) PlayerSendPlayerList()
func (*Entity) PlayerSendStatsUpdate ¶
func (p *Entity) PlayerSendStatsUpdate()
func (*Entity) RandomiseGenderName ¶
func (e *Entity) RandomiseGenderName()
func (*Entity) RemoveTargetLock ¶
func (n *Entity) RemoveTargetLock()
func (*Entity) StartRoutines ¶
func (e *Entity) StartRoutines()
func (*Entity) SyncDealerInventory ¶
func (*Entity) SyncDruggieTrade ¶
type Game ¶
type Game struct { DbConn *sql.DB // DB Connection Logout chan *Client // disconnected clients, gracefull logout Clients map[*Client]bool // connected clients Players map[*Entity]bool // connected clients Register chan *Client // pending new connections GlobalEvents chan protoreflect.ProtoMessage // global chat NewsFlash chan protoreflect.ProtoMessage // news flashes Movement chan protoreflect.ProtoMessage // player movement events World map[string]*City // the game world // contains filtered or unexported fields }
func (*Game) CheckNameTaken ¶
func (g *Game) CheckNameTaken(w http.ResponseWriter, r *http.Request)
func (*Game) GetPlayerClient ¶
func (*Game) GetUserCharacter ¶
func (g *Game) GetUserCharacter(userId uint64) (*Entity, *Coordinates, error)
func (*Game) HandleLogout ¶
func (*Game) HandleRegistration ¶
func (g *Game) HandleRegistration(w http.ResponseWriter, r *http.Request)
func (*Game) LoginPlayer ¶
func (g *Game) LoginPlayer(c *Client, p *Entity, k *Coordinates)
func (*Game) RenderConsoleUI ¶
func (g *Game) RenderConsoleUI()
type Inventory ¶
type Inventory struct { Items [settings.PlayerMaxInventory]*Item `json:"items"` Owner *Entity Equipment map[IType]*Item Mu sync.Mutex }
func NewInventory ¶
type Item ¶
type Item struct { ID string Name string Description string TemplateName string ItemType IType Condition float32 Amount int32 Price uint32 MinRep int64 BasePrice uint MaxPrice uint Damage uint ArmorGuns uint ArmorMelee uint AmmoWear float32 Inventory *Inventory Loc *Location UseEffect *ItemUseEffect }
func (*Item) GetAmmoWear ¶
func (*Item) GetArmorGuns ¶
func (*Item) GetArmorMelee ¶
func (*Item) GetDescription ¶
func (*Item) GetItemStats ¶
func (*Item) GetItemType ¶
func (*Item) GetQualitySuffix ¶
func (*Item) GetUseEffect ¶
func (i *Item) GetUseEffect() *ItemUseEffect
func (*Item) InspectName ¶
type ItemGameFrame ¶
type ItemGameFrame struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Condition float32 `json:"condition,omitempty"` ItemType IType `json:"type,omitempty"` Amount int32 `json:"amount,omitempty"` Price uint32 `json:"price,omitempty"` Damage uint `json:"damage,omitempty"` ArmorGuns uint `json:"armor_guns,omitempty"` ArmorMelee uint `json:"armor_melee,omitempty"` Equipped bool `json:"equipped,omitempty"` IsGear bool `json:"is_gear,omitempty"` HasUseEffect bool `json:"has_use_effect,omitempty"` }
type ItemSaveContainer ¶
type ItemTemplate ¶
type ItemUseEffect ¶
type KeyFloatValue ¶
type KeyIntValue ¶
type KeyStringValue ¶
type Location ¶
type Location struct { City *City Description string Coords Coordinates Players map[*Client]bool Npcs map[*Entity]bool Items map[*Item]bool PlayerJoin chan *Client NpcJoin chan *Entity AddItem chan *ItemMoved RemoveItem chan *ItemMoved Events chan *ClientResponse Respawn chan CombatAction Buildings []*Building // contains filtered or unexported fields }
type Movement ¶
type Movement struct { Origin Coordinates `json:"origin,omitempty"` Destination Coordinates `json:"destination,omitempty"` }
type NPCGameFrame ¶
type NPCType ¶
type NPCType int16
const ( DrugDealer NPCType = 0 DrugAddict NPCType = 1 Homeless NPCType = 2 Tweaker NPCType = 3 Bouncer NPCType = 4 Busker NPCType = 5 StreetVendor NPCType = 6 StreetGangMember NPCType = 7 Tourist NPCType = 8 Activist NPCType = 9 PoliceOfficer NPCType = 10 BeatCop NPCType = 11 DeliveryDriver NPCType = 12 )
type NpcTemplate ¶
type PlayerGameFrame ¶
type Rank ¶
type RegistrationBody ¶
type RegistrationResponse ¶
Source Files ¶
- api.go
- building-data.go
- building.go
- building_shop.go
- city-data.go
- city.go
- client.go
- combat.go
- command.go
- commands-buildings.go
- commands-data.go
- commands-items.go
- coordinates.go
- entity.go
- game.go
- gang.go
- inventory.go
- item.go
- items-data.go
- keyvalue.go
- location.go
- merchant_drugdealer.go
- merchant_druggie.go
- names-data.go
- npc-data.go
- npc.go
- player.go
- queries.go
- ranks.go
- responses.go
Click to show internal directories.
Click to hide internal directories.