[SEMI-MODULAR] Re-adds the stock market for cargo (#5441)

* this was embarrassingly easy to port

literal copy and paste and it works fine with only one line needing to be removed

* new lines keep the linter check happy

* begone single letter vars

* a

* b

* we lore friendly bois now (i think)

* Presidents use country names which I'd rather be corporation names

dab

Co-authored-by: Prodirus <prodirus@gmail.com>
This commit is contained in:
DuffCreeper
2021-05-07 02:48:59 +01:00
committed by GitHub
co-authored by Prodirus
parent ef5ffb781f
commit 9c4e52ed34
10 changed files with 1423 additions and 0 deletions
@@ -25,3 +25,4 @@
new /obj/item/circuitboard/machine/ore_silo(src)
new /obj/item/card/id/departmental_budget/car(src)
new /obj/item/clothing/suit/hooded/wintercoat/qm(src)
new /obj/item/circuitboard/computer/stockexchange(src) //SKYRAT EDIT - Adds stock exchange computer board to locker so QM has control over stonks
@@ -0,0 +1,125 @@
/proc/consonant()
return pick("B","C","D","F","G","H","J","K","L","M","N","P","Q","R","S","T","V","W","X","Y","Z")
/proc/vowel()
return pick("A", "E", "I", "O", "U")
/proc/ucfirst(var/string)
return "[uppertext(ascii2text(text2ascii(string, 1)))][copytext(string, 2)]"
/proc/ucfirsts(var/string)
var/list/split_text = splittext(string, " ")
var/list/position_list = list()
for (var/position in split_text)
position_list += ucfirst(position)
return jointext(position_list, " ")
GLOBAL_LIST_EMPTY(FrozenAccounts)
/proc/list_frozen()
for (var/frozen_accounts in GLOB.FrozenAccounts)
to_chat(usr, "[frozen_accounts]: [length(GLOB.FrozenAccounts[frozen_accounts])] borrows")
/datum/article
var/headline = "Something big is happening"
var/subtitle = "Investors panic as stock market collapses"
var/article = "God, it's going to be fun to randomly generate this."
var/author = "P. Pubbie"
var/spacetime = ""
var/opinion = 0
var/ticks = 0
var/datum/stock/about = null
var/outlet = ""
var/static/list/outlets = list()
var/static/list/default_tokens = list( \
"buy" = list("buy!", "buy, buy, buy!", "get in now!", "ride the share value to the stars!"), \
"company" = list("company", "corporation", "conglomerate", "enterprise", "venture"), \
"complete" = list("complete", "total", "absolute", "incredible"), \
"country" = list("Electra Networks", "Microman", "Solas Colony", "Anemone", "Beacon", "Protonetworks", "Lifeworth", "Tundra Lighting", "Illume", "Terra Corps", "Visage", "Night Co.", "Coblium", "Mars Federation", "Jungle Entertainment", "Wizardlife", "Hammer Security"), \
"development" = list("development", "unfolding of events", "turn of events", "new shit"), \
"dip" = list("dip", "fall", "plunge", "decrease"), \
"excited" = list("excited", "euphoric", "exhilarated", "thrilled", "stimulated"), \
"expand_influence" = list("expands their influence over", "continues to dominate", "gains traction in", "rolls their new product line out in"), \
"failure" = list("failure", "meltdown", "breakdown", "crash", "defeat", "wreck"), \
"famous" = list("famous", "prominent", "leading", "renowned", "expert"), \
"hit_shelves" = list("hit the shelves", "appeared on the market", "came out", "was released"), \
"industry" = list("industry", "sector"), \
"industrial" = list("industrial"), \
"jobs" = list("workers"), \
"negative_outcome" = list("it's not leaving the shelves", "nobody seems to care", "it's a huge money sink", "they have already pulled all advertising and marketing support"), \
"neutral_outcome" = list("it's not lifting off as expected", "it's not selling according to expectations", "it's only generating enough profit to cover the marketing and manufacturing costs", "it does not look like it will become a massive success", "it's experiencing modest sales"), \
"positive_outcome" = list("it's already sold out", "it has already sold over one billion units", "suppliers cannot keep up with the wild demand", "several companies using this new technology are already reporting a projected increase in profits"), \
"resounding" = list("resounding", "tremendous", "total", "massive", "terrific", "colossal"), \
"rise" = list("rise", "increase", "fly off the positive side of the charts", "skyrocket", "lift off"), \
"sell" = list("sell!", "sell, sell, sell!", "bail!", "abandon ship!", "get out before it's too late!", "evacuate!", "withdraw!"), \
"signifying" = list("signifying", "indicating", "implying", "displaying", "suggesting"), \
"sneak_peek" = list("review", "sneak peek", "preview", "exclusive look"), \
"stock_market" = list("stock market", "stock exchange"), \
"stockholder" = list("stockholder", "shareholder"), \
"success" = list("success", "triumph", "victory"), \
"this_time" = list("this week", "last week", "this month", "yesterday", "today", "a few days ago") \
)
/datum/article/New()
..()
if ((outlets.len && !prob(100 / (outlets.len + 1))) || !outlets.len)
var/outlet_name = generateOutletName()
if (!(outlet_name in outlets))
outlets[outlet_name] = list()
outlet = outlet_name
else
outlet = pick(outlets)
var/list/authors = outlets[outlet]
if ((authors.len && !prob(100 / (authors.len + 1))) || !authors.len)
var/author_name = generateAuthorName()
outlets[outlet] += author_name
author = author_name
else
author = pick(authors)
ticks = world.time
/datum/article/proc/generateOutletName()
var/list/locations = list("Earth", "Mars", "Luna", "Venus", "Ceres", "Pluto", "Ceti Epsilon", "Eos", "Terstan", "Deimos", "Space", "Neptune", "Mercury", "Terra", "Terstan", "Lorriman", "Cinu", "Himalia", "Yuklid", "Lordania", "Kingston", "Gaia", "Magnitka", "Artyom")
var/list/nouns = list("Post", "Herald", "Sun", "Tribune", "Mail", "Times", "Journal", "Report")
var/list/timely = list("Daily", "Hourly", "Weekly", "Biweekly", "Monthly", "Yearly")
switch(rand(1,2))
if (1)
return "The [pick(locations)] [pick(nouns)]"
if (2)
return "The [pick(timely)] [pick(nouns)]"
/datum/article/proc/generateAuthorName()
switch(rand(1,3))
if (1)
return "[consonant()]. [pick(GLOB.last_names)]"
if (2)
return "[prob(50) ? pick(GLOB.first_names_male) : pick(GLOB.first_names_female)] [consonant()].[prob(50) ? "[consonant()]. " : null] [pick(GLOB.last_names)]"
if (3)
return "[prob(50) ? pick(GLOB.first_names_male) : pick(GLOB.first_names_female)] \"[prob(50) ? pick(GLOB.first_names_male) : pick(GLOB.first_names_female)]\" [pick(GLOB.last_names)]"
/datum/article/proc/formatSpacetime()
var/ticksc = round(ticks/100)
ticksc = ticksc % 100000
var/ticksp = "[ticksc]"
while (length(ticksp) < 5)
ticksp = "0[ticksp]"
spacetime = "[ticksp][time2text(world.realtime, "MM")][time2text(world.realtime, "DD")][text2num(time2text(world.realtime, "YYYY"))+540]"
/datum/article/proc/formatArticle()
if (spacetime == "")
formatSpacetime()
var/output = "<div class='article'><div class='headline'>[headline]</div><div class='subtitle'>[subtitle]</div><div class='article-body'>[article]</div><div class='author'>[author]</div><div class='timestamp'>[spacetime]</div></div>"
return output
/datum/article/proc/detokenize(var/token_string, var/list/industry_tokens, var/list/product_tokens = list())
var/list/T_list = default_tokens.Copy()
for (var/token in industry_tokens)
T_list[token] = industry_tokens[token]
for (var/token in product_tokens)
T_list[token] = list(product_tokens[token])
for (var/token in T_list)
token_string = replacetext(token_string, "%[token]%", pick(T_list[token]))
return ucfirst(token_string)
@@ -0,0 +1,325 @@
/obj/machinery/computer/stockexchange
name = "stock exchange computer"
icon = 'icons/obj/computer.dmi'
icon_state = "oldcomp"
icon_screen = "stock_computer"
icon_keyboard = "no_keyboard"
var/logged_in = "Cargo Department"
var/vmode = 1
circuit = /obj/item/circuitboard/computer/stockexchange
light_color = LIGHT_COLOR_GREEN
/obj/machinery/computer/stockexchange/Initialize()
. = ..()
logged_in = "SS13 Cargo Department"
/obj/machinery/computer/stockexchange/proc/balance()
var/datum/bank_account/dept_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if (!logged_in)
return 0
return dept_account.account_balance
/obj/machinery/computer/stockexchange/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/computer/stockexchange/attack_robot(mob/user)
return attack_hand(user)
/obj/machinery/computer/stockexchange/attack_hand(var/mob/user)
if(..())
return
user.machine = src
var/css={"<style>
.change {
font-weight: bold;
font-family: monospace;
}
.up {
background: #00a000;
}
.down {
background: #a00000;
}
.stable {
width: 100%
border-collapse: collapse;
border: 1px solid #305260;
border-spacing: 4px 4px;
}
.stable td, .stable th {
border: 1px solid #305260;
padding: 0px 3px;
}
.bankrupt {
border: 1px solid #a00000;
background: #a00000;
}
a.updated {
color: red;
}
</style>"}
var/dat = "<html><head><title>[station_name()] Stock Exchange</title>[css]</head><body>"
dat += "<span class='user'>Welcome, <b>[station_name()] Cargo Department</b></span><br><span class='balance'><b>Credits:</b> [balance()] </span><br>"
for (var/datum/stock/last_stock in GLOB.stockExchange.last_read)
var/list/last_read_stock = GLOB.stockExchange.last_read[last_stock]
if (!(logged_in in last_read_stock))
last_read_stock[logged_in] = 0
dat += "<b>View mode:</b> <a href='?src=[REF(src)];cycleview=1'>[vmode ? "Compact" : "Full"]</a> "
dat += "<b>Stock Transaction Log:</b> <a href='?src=[REF(src)];show_logs=1'>Check</a><br>"
dat += "<h3>Listed stocks</h3>"
if (vmode == 0)
for (var/datum/stock/current_stock in GLOB.stockExchange.stocks)
var/mystocks = 0
if (logged_in && (logged_in in current_stock.shareholders))
mystocks = current_stock.shareholders[logged_in]
dat += "<hr /><div class='stock'><span class='company'>[current_stock.name]</span> <span class='s_company'>([current_stock.short_name])</span>[current_stock.bankrupt ? " <b style='color:red'>BANKRUPT</b>" : null]<br>"
if (current_stock.last_unification)
dat += "<b>Unified shares</b> [DisplayTimeText(world.time - current_stock.last_unification)] ago.<br>"
dat += "<b>Current value per share:</b> [current_stock.current_value] | <a href='?src=[REF(src)];viewhistory=[REF(current_stock)]'>View history</a><br><br>"
dat += "You currently own <b>[mystocks]</b> shares in this company. There are [current_stock.available_shares] purchasable shares on the market currently.<br>"
if (current_stock.bankrupt)
dat += "You cannot buy or sell shares in a bankrupt company!<br><br>"
else
dat += "<a href='?src=[REF(src)];buyshares=[REF(current_stock)]'>Buy shares</a> | <a href='?src=[REF(src)];sellshares=[REF(current_stock)]'>Sell shares</a><br><br>"
dat += "<b>Prominent products:</b><br>"
for (var/prod in current_stock.products)
dat += "<i>[prod]</i><br>"
var/news = 0
if (logged_in)
var/list/last_read_stock = GLOB.stockExchange.last_read[current_stock]
var/last_read_time = last_read_stock[logged_in]
for (var/datum/article/current_article in current_stock.articles)
if (current_article.ticks > last_read_time)
news = 1
break
if (!news)
for (var/datum/stockEvent/current_stock_event in current_stock.events)
if (current_stock_event.last_change > last_read_time && !current_stock_event.hidden)
news = 1
break
dat += "<a href='?src=[REF(src)];archive=[REF(current_stock)]'>View news archives</a>[news ? " <span style='color:red'>(updated)</span>" : null]</div>"
else if (vmode == 1)
dat += "<b>Actions:</b> + Buy, - Sell, (A)rchives, (H)istory<br><br>"
dat += "<table class='stable'>"
dat += "<tr><th>&nbsp;</th><th>ID</th><th>Name</th><th>Value</th><th>Owned</th><th>Avail</th><th>Actions</th></tr>"
for (var/datum/stock/current_stock in GLOB.stockExchange.stocks)
var/mystocks = 0
if (logged_in && (logged_in in current_stock.shareholders))
mystocks = current_stock.shareholders[logged_in]
if(current_stock.bankrupt)
dat += "<tr class='bankrupt'>"
else
dat += "<tr>"
if(current_stock.disp_value_change > 0)
dat += "<td class='change up'>+</td>"
else if(current_stock.disp_value_change < 0)
dat += "<td class='change down'>-</td>"
else
dat += "<td class='change'>=</td>"
dat += "<td><b>[current_stock.short_name]</b></td>"
dat += "<td>[current_stock.name]</td>"
if(!current_stock.bankrupt)
dat += "<td>[current_stock.current_value]</td>"
else
dat += "<td>0</td>"
if(mystocks)
dat += "<td><b>[mystocks]</b></td>"
else
dat += "<td>0</td>"
dat += "<td>[current_stock.available_shares]</td>"
var/news = 0
if (logged_in)
var/list/last_read_stock = GLOB.stockExchange.last_read[current_stock]
var/last_read_time = last_read_stock[logged_in]
for (var/datum/article/current_article in current_stock.articles)
if (current_article.ticks > last_read_time)
news = 1
break
if (!news)
for (var/datum/stockEvent/current_stock_event in current_stock.events)
if (current_stock_event.last_change > last_read_time && !current_stock_event.hidden)
news = 1
break
dat += "<td>"
if (current_stock.bankrupt)
dat += "<span class='linkOff'>+</span> <span class='linkOff'>-</span> "
else
dat += "<a href='?src=[REF(src)];buyshares=[REF(current_stock)]'>+</a> <a href='?src=[REF(src)];sellshares=[REF(current_stock)]'>-</a> "
dat += "<a href='?src=[REF(src)];archive=[REF(current_stock)]' class='[news ? "updated" : "default"]'>(A)</a> <a href='?src=[REF(src)];viewhistory=[REF(current_stock)]'>(H)</a></td>"
dat += "</tr>"
dat += "</table>"
dat += "</body></html>"
var/datum/browser/popup = new(user, "computer", "Stock Exchange", 600, 600)
popup.set_content(dat)
popup.open()
return
/obj/machinery/computer/stockexchange/proc/sell_some_shares(var/datum/stock/current_stock, var/mob/user)
if (!user || !current_stock)
return
var/user_logged_in = logged_in
if (!user_logged_in)
to_chat(user, "<span class='danger'>No active account on the console!</span>")
return
var/datum/bank_account/dept_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/dept_account_balance = dept_account.account_balance
var/avail = current_stock.shareholders[logged_in]
if (!avail)
to_chat(user, "<span class='danger'>This account does not own any shares of [current_stock.name]!</span>")
return
var/price = current_stock.current_value
var/amt = round(input(user, "How many shares? \n(Have: [avail], unit price: [price])", "Sell shares in [current_stock.name]", 0) as num|null)
amt = min(amt, current_stock.shareholders[logged_in])
if (!user || (!(user in range(1, src)) && iscarbon(user)))
return
if (!amt)
return
if (user_logged_in != logged_in)
return
dept_account_balance = dept_account.account_balance
if (!isnum(dept_account_balance))
to_chat(user, "<span class='danger'>No active account on the console!</span>")
return
var/total = amt * current_stock.current_value
if (!current_stock.sellShares(logged_in, amt))
to_chat(user, "<span class='danger'>Could not complete transaction.</span>")
return
to_chat(user, "<span class='notice'>Sold [amt] shares of [current_stock.name] at [current_stock.current_value] a share for [total] credits.</span>")
GLOB.stockExchange.add_log(/datum/stock_log/sell, user.name, current_stock.name, amt, current_stock.current_value, total)
/obj/machinery/computer/stockexchange/proc/buy_some_shares(var/datum/stock/current_stock, var/mob/user)
if (!user || !current_stock)
return
var/user_logged_in = logged_in
if (!user_logged_in)
to_chat(user, "<span class='danger'>No active account on the console!</span>")
return
var/dept_account_balance = balance()
if (!isnum(dept_account_balance))
to_chat(user, "<span class='danger'>No active account on the console!</span>")
return
var/avail = current_stock.available_shares
var/price = current_stock.current_value
var/canbuy = round(dept_account_balance / price)
var/amt = round(input(user, "How many shares? \n(Available: [avail], unit price: [price], can buy: [canbuy])", "Buy shares in [current_stock.name]", 0) as num|null)
if (!user || (!(user in range(1, src)) && iscarbon(user)))
return
if (user_logged_in != logged_in)
return
dept_account_balance = balance()
if (!isnum(dept_account_balance))
to_chat(user, "<span class='danger'>No active account on the console!</span>")
return
amt = min(amt, current_stock.available_shares, round(dept_account_balance / current_stock.current_value))
if (!amt)
return
if (!current_stock.buyShares(logged_in, amt))
to_chat(user, "<span class='danger'>Could not complete transaction.</span>")
return
var/total = amt * current_stock.current_value
to_chat(user, "<span class='notice'>Bought [amt] shares of [current_stock.name] at [current_stock.current_value] a share for [total] credits.</span>")
GLOB.stockExchange.add_log(/datum/stock_log/buy, user.name, current_stock.name, amt, current_stock.current_value, total)
/obj/machinery/computer/stockexchange/proc/do_borrowing_deal(var/datum/borrow/borrow_deal, var/mob/user)
if (borrow_deal.stock.borrow(borrow_deal, logged_in))
to_chat(user, "<span class='notice'>You successfully borrowed [borrow_deal.share_amount] shares. Deposit: [borrow_deal.deposit].</span>")
GLOB.stockExchange.add_log(/datum/stock_log/borrow, user.name, borrow_deal.stock.name, borrow_deal.share_amount, borrow_deal.deposit)
else
to_chat(user, "<span class='danger'>Could not complete transaction. Check your account balance.</span>")
/obj/machinery/computer/stockexchange/Topic(href, href_list)
if (..())
return 1
if (!usr || (!(usr in range(1, src)) && iscarbon(usr)))
usr.machine = src
if (href_list["viewhistory"])
var/datum/stock/stock_history = locate(href_list["viewhistory"]) in GLOB.stockExchange.stocks
if (stock_history)
stock_history.displayValues(usr)
if (href_list["logout"])
logged_in = null
if (href_list["buyshares"])
var/datum/stock/avail_stocks = locate(href_list["buyshares"]) in GLOB.stockExchange.stocks
if (avail_stocks)
buy_some_shares(avail_stocks, usr)
if (href_list["sellshares"])
var/datum/stock/avail_stocks = locate(href_list["sellshares"]) in GLOB.stockExchange.stocks
if (avail_stocks)
sell_some_shares(avail_stocks, usr)
if (href_list["show_logs"])
var/dat = "<html><head><title>Stock Transaction Logs</title></head><body><h2>Stock Transaction Logs</h2><div><a href='?src=[REF(src)];show_logs=1'>Refresh</a></div><br>"
for(var/stock_logs in GLOB.stockExchange.logs)
var/datum/stock_log/current_stock_log = stock_logs
if(istype(current_stock_log, /datum/stock_log/buy))
dat += "[current_stock_log.time] | <b>[current_stock_log.user_name]</b> bought <b>[current_stock_log.stocks]</b> stocks at [current_stock_log.shareprice] a share for <b>[current_stock_log.money]</b> total credits in <b>[current_stock_log.company_name]</b>.<br>"
continue
if(istype(current_stock_log, /datum/stock_log/sell))
dat += "[current_stock_log.time] | <b>[current_stock_log.user_name]</b> sold <b>[current_stock_log.stocks]</b> stocks at [current_stock_log.shareprice] a share for <b>[current_stock_log.money]</b> total credits from <b>[current_stock_log.company_name]</b>.<br>"
continue
if(istype(current_stock_log, /datum/stock_log/borrow))
dat += "[current_stock_log.time] | <b>[current_stock_log.user_name]</b> borrowed <b>[current_stock_log.stocks]</b> stocks with a deposit of <b>[current_stock_log.money]</b> credits in <b>[current_stock_log.company_name]</b>.<br>"
continue
var/datum/browser/popup = new(usr, "stock_logs", "Stock Transaction Logs", 600, 400)
popup.set_content(dat)
popup.open()
if (href_list["archive"])
var/datum/stock/stock_archive = locate(href_list["archive"])
if (logged_in && logged_in != "")
var/list/last_read_stock = GLOB.stockExchange.last_read[stock_archive]
last_read_stock[logged_in] = world.time
var/dat = "<html><head><title>News feed for [stock_archive.name]</title></head><body><h2>News feed for [stock_archive.name]</h2><div><a href='?src=[REF(src)];archive=[REF(stock_archive)]'>Refresh</a></div>"
dat += "<div><h3>Events</h3>"
var/p = 0
for (var/datum/stockEvent/stock_event in stock_archive.events)
if (stock_event.hidden)
continue
if (p > 0)
dat += "<hr>"
dat += "<div><b style='font-size:1.25em'>[stock_event.current_title]</b><br>[stock_event.current_desc]</div>"
p++
dat += "</div><hr><div><h3>Articles</h3>"
p = 0
for (var/datum/article/stock_article in stock_archive.articles)
if (p > 0)
dat += "<hr>"
dat += "<div><b style='font-size:1.25em'>[stock_article.headline]</b><br><i>[stock_article.subtitle]</i><br><br>[stock_article.article]<br>- [stock_article.author], [stock_article.spacetime] (via <i>[stock_article.outlet]</i>)</div>"
p++
dat += "</div></body></html>"
var/datum/browser/popup = new(usr, "archive_[stock_archive.name]", "Stock News", 600, 400)
popup.set_content(dat)
popup.open()
if (href_list["cycleview"])
vmode++
if (vmode > 1)
vmode = 0
src.add_fingerprint(usr)
src.updateUsrDialog()
@@ -0,0 +1,3 @@
/obj/item/circuitboard/computer/stockexchange
name = "circuit board (Stock Exchange Console)"
build_path = /obj/machinery/computer/stockexchange
@@ -0,0 +1,228 @@
#define TIME_MULTIPLIER 0.7 // so I can speed up/slow down shit
/datum/stockEvent
var/name = "event"
var/next_phase = 0
var/datum/stock/company = null
var/current_title = "A company holding a pangalactic conference in the Seattle Conference Center, Seattle, Earth"
var/current_desc = "We will continue to monitor their stocks as the situation unfolds."
var/phase_id = 0
var/hidden = 0
var/finished = 0
var/last_change = 0
/datum/stockEvent/process()
if (finished)
return
if (world.time > next_phase)
transition()
/datum/stockEvent/proc/transition()
return
/datum/stockEvent/proc/spacetime(var/ticks)
var/seconds = round(ticks / 10)
var/minutes = round(seconds / 60)
seconds -= minutes * 60
return "[minutes] minute(s) and [seconds] second(s)"
/datum/stockEvent/product
name = "product"
var/product_name = ""
var/datum/article/product_article = null
var/effect = 0
/datum/stockEvent/product/New(var/datum/stock/new_stock)
company = new_stock
var/mins = rand(5*TIME_MULTIPLIER,20*TIME_MULTIPLIER)
next_phase = mins * (600*TIME_MULTIPLIER) + world.time
current_title = "Product demo"
current_desc = new_stock.industry.detokenize("[new_stock.name] will unveil a new product on an upcoming %industrial% conference held at spacetime [spacetime(next_phase)]")
new_stock.addEvent(src)
/datum/stockEvent/product/transition()
last_change = world.time
switch (phase_id)
if (0)
next_phase = world.time + rand(300*TIME_MULTIPLIER, 600*TIME_MULTIPLIER) * (10*TIME_MULTIPLIER)
product_name = company.industry.generateProductName(company.name)
current_title = "Product release: [product_name]"
current_desc = "[company.name] unveiled their newest product, [product_name], at a conference. Product release is expected to happen at spacetime [spacetime(next_phase)]."
var/datum/article/new_article = company.industry.generateInCharacterProductArticle(product_name, company)
product_article = new_article
effect = new_article.opinion + rand(-1, 1)
company.affectPublicOpinion(effect)
phase_id = 1
if (1)
finished = 1
hidden = 1
company.addArticle(product_article)
effect += product_article.opinion * 5
company.affectPublicOpinion(effect)
phase_id = 2
company.generateEvent(type)
/datum/stockEvent/bankruptcy
name = "bankruptcy"
var/effect = 0
var/bailout_millions = 0
/datum/stockEvent/bankruptcy/New(var/datum/stock/bankrupt_stock)
hidden = 1
company = bankrupt_stock
var/mins = rand(9*TIME_MULTIPLIER,60*TIME_MULTIPLIER)
bailout_millions = rand(70, 190)
next_phase = mins * 300*TIME_MULTIPLIER + world.time
current_title = ""
current_desc = ""
bankrupt_stock.addEvent(src)
/datum/stockEvent/bankruptcy/transition()
switch (phase_id)
if (0)
next_phase = world.time + rand(300*TIME_MULTIPLIER, 600*TIME_MULTIPLIER) * (10*TIME_MULTIPLIER)
var/datum/article/bankrupt_article = generateBankruptcyArticle()
if (!bankrupt_article.opinion)
effect = rand(5) * (prob(50) ? -1 : 1)
else
effect = prob(25) ? -bankrupt_article.opinion * rand(8) : bankrupt_article.opinion * rand(4)
company.addArticle(bankrupt_article)
company.affectPublicOpinion(rand(-6, -3))
hidden = 0
current_title = "Bailout pending due to bankruptcy"
current_desc = "The government prepared a press release, which will occur at spacetime [spacetime(next_phase)]."
phase_id = 1
if (1)
next_phase = world.time + rand(300*TIME_MULTIPLIER, 600*TIME_MULTIPLIER) * (10*TIME_MULTIPLIER)
finished = 1
if (effect <= -5 && prob(10))
current_title = "[company.name]: Complete crash"
current_desc = "The company had gone bankrupt, was not bailed out and could not recover. No further stock trade will take place. All shares in the company are effectively worthless."
company.bankrupt = 1
for (var/shareholder_amount in company.shareholders)
var/amt = company.shareholders[shareholder_amount]
GLOB.stockExchange.balanceLog(shareholder_amount, -amt * company.current_value)
company.shareholders = list()
company.current_value = 0
company.borrow_brokers = list()
GLOB.stockExchange.generateStocks(1)
var/bailout = (effect > 0 && prob(80)) || (effect < 0 && prob(20))
current_title = "[company.name] [bailout ? "bailed out" : "on a painful rebound"]"
if (bailout)
current_desc = "The company has been bailed out by the government. Investors are highly optimistic."
company.affectPublicOpinion(abs(effect) * 2)
else
current_desc = "The company was not bailed out, but managed to crawl out of bankruptcy. Stockholder trust is severely dented."
company.affectPublicOpinion(-abs(effect) / 2)
company.generateEvent(type)
/datum/stockEvent/bankruptcy/proc/generateBankruptcyArticle()
var/datum/article/bankrupt_article = new
var/list/bankrupt_reason = list("investor pessimism", "failure of product lines", "economic recession", "overblown inflation", "overblown deflation", "collapsed pyramid schemes", "a Ponzi scheme", "economic terrorism", "extreme hedonism", "unfavourable economic climate", "rampant government corruption", "divine conspiracy", "some total bullshit", "volatile plans")
bankrupt_article.about = company
bankrupt_article.headline = pick( "[company.name] filing for bankruptcy", \
"[company.name] unable to pay, investors run", \
"[company.name] crashes, in foreclosure", \
"[company.name] in dire need of credits")
bankrupt_article.subtitle = "Investors panic, bailout pending"
if (prob(15))
bankrupt_article.opinion = rand(-1, 1)
var/article = "Another one might bite the dust: [company.current_trend > 0 ? "despite their positive trend" : "in line with their failing model"], [company.name] files for bankruptcy citing [pick(bankrupt_reason)]. The president of %country% has been asked to bail the company out, "
if (!bankrupt_article.opinion)
article += "but no answer has been given by the government to date. Our tip to stay safe is: %sell%"
else if (bankrupt_article.opinion > 0)
article += "and the government responded positively. When the share value hits its lowest, it is a safe bet to %buy%"
else
article += "but the outlook is not good. For investors, now would be an ideal time to %sell%"
bankrupt_article.article = bankrupt_article.detokenize(article, company.industry.tokens)
return bankrupt_article
/datum/stockEvent/arrest
name = "arrest"
var/female = 0
var/tname = "Elvis Presley"
var/position = "CEO"
var/offenses = "murder"
var/effect = 0
/datum/stockEvent/arrest/New(var/datum/stock/stock_arrest)
hidden = 1
company = stock_arrest
var/mins = rand(10*TIME_MULTIPLIER, 35*TIME_MULTIPLIER)
next_phase = mins * 600*TIME_MULTIPLIER + world.time
current_title = ""
current_desc = ""
female = prob(50)
if (prob(50))
position = "C[prob(20) ? vowel() : consonant()]O"
else
position = ucfirsts(company.industry.detokenize("Lead %industrial% Engineer"))
offenses = ""
var/list/offense_list = list("corruption", "murder", "grand theft", "assault", "battery", "drug possession", "burglary", "theft", "grand sabotage", "bribery",
"disorderly conduct", "treason", "sedition", "shoplifting", "tax evasion", "tax fraud", "insurance fraud", "perjury", "kidnapping", "manslaughter", "vandalism", "forgery", "extortion", "embezzlement",
"public indecency", "public intoxication", "trespassing", "loitering", "littering", "vigilantism", "squatting", "panhandling", "arson", "spacepodjacking", "shuttlejacking", "carjacking", "singularityjacking",
"dereliction of duty", "spacecraft piracy", "music piracy", "tabletop game piracy", "software piracy", "escaping from space prison", "seniornapping", "clownnapping", "corginapping", "catnapping",
"sleeping on the job", "terrorism", "counterterrorism", "drug distribution", "insubordination", "jaywalking", "owning a computer", "owning a cellphone", "owning a PDA", "owning a pAI", "adultery",
"committing an unnatural act with another person", "corrupting public morals", "skateboarding without a license", "shitcurity", "bestiality", "erotic roleplay", "accidentally strangling a prostitute")
while (prob(60) && offense_list.len > 2)
var/offense = pick(offense_list)
offense_list -= offense
offense = "[prob(20) ? "attempted " : (prob(20) ? "being accessory to " : null)][offense][prob(5) ? " of the [pick("first", "second", "third", "fourth", "fifth", "sixth")] degree" : null]"
if (offenses == "")
offenses = offense
else
offenses += ", [offense]"
offenses += " and [prob(20) ? "attempted " : null][pick(offense_list)]" // lazy
stock_arrest.addEvent(src)
/datum/stockEvent/arrest/transition()
switch (phase_id)
if (0)
tname = "[female ? pick(GLOB.first_names_female) : pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
next_phase = world.time + rand(300*TIME_MULTIPLIER, 600*TIME_MULTIPLIER) * (10*TIME_MULTIPLIER)
var/datum/article/arrest_article = generateArrestArticle()
if (!arrest_article.opinion)
effect = rand(5) * (prob(50) ? -1 : 1)
else
effect = prob(25) ? -arrest_article.opinion * rand(5) : arrest_article.opinion * rand(3)
company.addArticle(arrest_article)
company.affectPublicOpinion(rand(-3, -1))
hidden = 0
current_title = "Trial of [tname] ([position]) scheduled"
current_desc = "[female ? "She": "He"] has been charged with [offenses]; the trial is scheduled to occur at spacetime [spacetime(next_phase)]."
phase_id = 1
if (1)
next_phase = world.time + rand(300*TIME_MULTIPLIER, 600*TIME_MULTIPLIER) * (10*TIME_MULTIPLIER)
finished = 1
current_title = "[tname] [effect > 0 ? "acquitted" : "found guilty"]"
if (effect > 0)
current_desc = "The accused has been acquitted of all charges. Investors optimistic."
else
current_desc = "The accused has been found guilty of all charges. Investor trust takes massive hit."
company.affectPublicOpinion(effect)
company.generateEvent(type)
/datum/stockEvent/arrest/proc/generateArrestArticle()
var/datum/article/arrest_article = new
arrest_article.about = company
arrest_article.headline = company.industry.detokenize(pick( \
"[tname], [position] of [company.name] arrested", \
"[position] of [company.name] facing jail time", \
"[tname] behind bars", \
"[position] of %industrial% company before trial", \
"Police arrest [tname] in daring raid", \
"Job vacancy ahead: [company.name]'s [position] in serious trouble"))
arrest_article.subtitle = "[arrest_article.author] reporting directly from the courtroom"
if (prob(15))
arrest_article.opinion = rand(-1, 1)
var/article = "[pick("Security", "Law enforcement")] forces issued a statement that [tname], the [position] of [company.name], the %famous% %industrial% %company% was arrested %this_time%. The trial has been scheduled and the statement reports that the arrested individual is being charged with [offenses]. "
if (!arrest_article.opinion)
article += "While we cannot predict the outcome of this trial, our tip to stay safe is: %sell%"
else if (arrest_article.opinion > 0)
article += "Our own investigation shows that these charges are baseless and the arrest is most likely a publicity stunt. Our advice? You should %buy%"
else
article += "[tname] has a prior history of similar misdeeds and we're confident the charges will stand. For investors, now would be an ideal time to %sell%"
arrest_article.article = arrest_article.detokenize(article, company.industry.tokens)
return arrest_article
@@ -0,0 +1,233 @@
/datum/industry
var/name = "Industry"
var/list/tokens = list()
var/list/title_templates = list("The brand new %product_name% by %company_name% will revolutionize %industry%", \
"%jobs% rejoice as %product_name% hits shelves", \
"Does %product_name% threaten to reorganize the %industrial% status quo?", \
"%company_name% headed toward corporate renaissance with %product_name%")
var/list/title_templates_neutral = list("%product_name%: as if nothing happened", \
"Nothing new but the name: %product_name% not quite exciting %jobs%", \
"Same old %company_name%, same old product", \
"%product_name% underwhelms, but sells")
var/list/title_templates_bad = list("%product_name% shaping up to be the disappointment of the century", \
"Recipe for disaster: %company_name% releases %product_name%", \
"Atrocious quality - %jobs% boycott %product_name%", \
"%product_name%: Inside the worst product launch in recent history")
var/list/title_templates_ooc = list("%company_name% is looking to enter the %industry% playing field with %product_name%", \
"%company_name% broadens spectrum, %product_name% is their latest and greatest")
var/list/subtitle_templates = list( "%author% investigates whether or not you should invest!", \
"%outlet%'s very own %author% takes it to the magnifying glass", \
"%outlet% lets you know if you should use it", \
"Read our top tips for investors", \
"%author% wants you to know if it's a safe bet to buy")
/datum/industry/proc/generateProductName(var/company_name)
return
/datum/industry/proc/generateInCharacterProductArticle(var/product_name, var/datum/stock/current_stock)
var/datum/article/new_article = new
var/list/add_tokens = list("company_name" = current_stock.name, "product_name" = product_name, "outlet" = new_article.outlet, "author" = new_article.author)
new_article.about = current_stock
new_article.opinion = rand(-1, 1)
new_article.subtitle = new_article.detokenize(pick(subtitle_templates), tokens, add_tokens)
var/article = {"%company_name% %expand_influence% %industry%. [ucfirst(product_name)] %hit_shelves% %this_time% "}
if (new_article.opinion > 0)
new_article.headline = new_article.detokenize(pick(title_templates), tokens, add_tokens)
article += "but %positive_outcome%, %signifying% the %resounding% %success% the product is. The %stock_market% is %excited% over this %development%, and %stockholder% optimism is expected to %rise% as well as the stock value. Our advice: %buy%."
else if (new_article.opinion == 0)
new_article.headline = new_article.detokenize(pick(title_templates_neutral), tokens, add_tokens)
article += "but %neutral_outcome%. For the average %stockholder%, no significant change on the market will be apparent over this %development%. Our advice is to continue investing as if this product was never released."
else
new_article.headline = new_article.detokenize(pick(title_templates_bad), tokens, add_tokens)
article += "but %negative_outcome%. Following this %complete% %failure%, %stockholder% optimism and stock value are projected to %dip%. Our advice: %sell%."
new_article.article = new_article.detokenize(article, tokens, add_tokens)
return new_article
/datum/industry/proc/detokenize(var/str)
for (var/token in tokens)
str = replacetext(str, "%[token]%", pick(tokens[token]))
return str
/datum/industry/agriculture
name = "Agriculture"
tokens = list( \
"industry" = list("agriculture", "farming", "botany", "horticulture", "hydroponics"), \
"industrial" = list("agricultural", "horticultural", "botanical"), \
"jobs" = list("farmers", "agricultural experts", "botanists", "assistant gardeners")
)
title_templates = list( "The brand new %product_name% by %company_name% will revolutionize %industry%", \
"%jobs% rejoice as %product_name% hits shelves", \
"Does %product name% threaten to reorganize the %industrial% status quo?", \
"Took it for a field trip: our first %sneak_peek% of %product_name%.", \
"Reaping the fruits of %product_name% - %sneak_peek% by %author%", \
"Cultivating a new %industrial% future with %product_name%", \
"%company_name% grows and thrives: %product_name% now on the farmer's market", \
"It's almost harvest season: %product_name% promises to ease your life", \
"Become the best on the farmer's market with %product_name%", \
"%product_name%: a gene-modified reimagination of an age-old classic")
title_templates_ooc = list( "%company_name% is looking to enter the %industry% playing field with %product_name%", \
"A questionable decision: %product_name% grown on the soil of %company_name%", \
"%company_name% broadens spectrum, %product_name% is their latest and greatest", \
"Will %company_name% grow on %industrial% wasteland? Owners of %product_name% may decide", \
"%company_name% looking to reap profits off the %industrial% sector with %product_name%")
/datum/industry/agriculture/generateProductName(var/company_name)
var/list/products = list("water tank", "cattle prod", "scythe", "plough", "sickle", "cultivator", "loy", "spade", "hoe", "daisy grubber", "cotton gin")
var/list/prefix = list("[company_name]'s ", "the [company_name] ", "the fully automatic ", "the full-duplex ", "the semi-automatic ", "the drone-mounted ", "the industry-leading ", "the world-class ")
var/list/suffix = list(" of farming", " multiplex", " +[rand(1,15)]", " [consonant()][rand(1000, 9999)]", " hybrid", " maximus", " extreme")
return "[pick(prefix)][pick(products)][pick(suffix)]"
/datum/industry/it
name = "Information Technology"
tokens = list( \
"industry" = list("information technology", "computing", "computer industry"), \
"industrial" = list("information technological", "computing", "computer industrial"), \
"jobs" = list("coders", "electricians", "engineers", "programmers", "devops experts", "developers")
)
/datum/industry/it/proc/latin_number(n)
if (n < 20 || !(n % 10))
switch(n)
if (0)
return "Nihil"
if (1)
return "Unus"
if (2)
return "Duo"
if (3)
return "Tres"
if (4)
return "Quattour"
if (5)
return "Quinque"
if (6)
return "Sex"
if (7)
return "Septem"
if (8)
return "Octo"
if (9)
return "Novem"
if (10)
return "Decim"
if (11)
return "Undecim"
if (12)
return "Duodecim"
if (13)
return "Tredecim"
if (14)
return "Quattourdecim"
if (15)
return "Quindecim"
if (16)
return "Sedecim"
if (17)
return "Septdecim"
if (18)
return "Duodeviginti"
if (19)
return "Undeviginti"
if (20)
return "Viginti"
if (30)
return "Triginta"
if (40)
return "Quadriginta"
if (50)
return "Quinquaginta"
if (60)
return "Sexaginta"
if (70)
return "Septuaginta"
if (80)
return "Octoginta"
if (90)
return "Nonaginta"
else
return "[latin_number(n - (n % 10))] [lowertext(latin_number(n % 10))]"
/datum/industry/it/generateProductName(var/company_name)
var/list/products = list("generator", "laptop", "keyboard", "memory card", "display", "operating system", "processor", "graphics card", "nanobots", "power supply", "pAI", "mech", "capacitor", "cell")
var/list/prefix = list("the [company_name] ", "the high performance ", "the mobile ", "the portable ", "the professional ", "the extreme ", "the incredible ", "the blazing fast ", "the bleeding edge ", "the bluespace-powered ", null)
var/latin = pick(consonant(), "Seed ", "Radiant ", "Robust ", "Pentathon ", "Athlete ", "Phantom ", "Semper Fi ")
var/random_number = rand(0,99)
var/prefix2 = "[latin][random_number][prob(5) ? " " + latin_number(random_number) : null]"
return "[pick(prefix)][prefix2] [pick(products)]"
/datum/industry/communications
name = "Communications"
tokens = list( \
"industry" = list("telecommunications", "telecomms"), \
"industrial" = list("telecommunicational"), \
"jobs" = list("electrical engineers", "microengineers", "developers")
)
/datum/industry/communications/generateProductName(var/company_name)
var/list/products = list("mobile phone", "PDA", "tablet computer", "newscaster", "social network")
var/list/prefix = list("the [company_name] ", "the high performance ", "the mobile ", "the portable ", "the professional ", "the extreme ", "the incredible ", "the blazing fast ", "the bleeding edge ", null)
var/L = pick("[lowertext(consonant())]Phone ", "Universe ", "Xperience ", "Next ", "Engin Y ", "Cyborg ", "[consonant()]")
var/N = rand(1,99)
var/prefix2 = "[L][N][prob(25) ? pick(" Tiny", " Mini", " Micro", " Slim", " Water", " Air", " Fire", " Earth", " Nano", " Pico", " Femto", " Planck") : null]"
return "[pick(prefix)][prefix2] [pick(products)]"
/datum/industry/health
name = "Medicine"
tokens = list( \
"industry" = list("medicine"), \
"industrial" = list("medicinal"), \
"jobs" = list("medical doctors", "nurses", "paramedics", "psychologists", "psychiatrists", "chemists")
)
/datum/industry/health/generateProductName(var/company_name)
var/list/prefix = list("amino", "nucleo", "nitro", "panto", "meth", "eth", "as", "algo", "coca", "hero", "lotsu", "opiod", "morph", "trinitro", "prop", "but", "acet", "acyclo", "lansop", "dyclo", "hydro", "oxycod", "vicod", "cannabi", "cryo", "dex", "chloro")
var/list/suffix = list("phen", "pirin", "pyrine", "ane", "amphetamine", "prazoline", "ine", "yl", "amine", "aminophen", "one", "ide", "phenate", "anol", "toulene", "glycerine", "vir", "tol", "trinic", "oxide")
var/list/uses = list("antidepressant", "analgesic", "anesthetic", "antiretroviral", "antiviral", "antibiotic", "cough drop", "depressant", "hangover cure", "homeopathic", "fertility drug", "hypnotic", "narcotic", "laxative", "multivitamin", "patch", "purgative", "relaxant", "steroid", "sleeping pill", "suppository", "tranquilizer")
return "[pick(prefix)][pick(suffix)], the [pick(uses)]"
/datum/industry/consumer
name = "Consumer"
tokens = list( \
"industry" = list("shops", "stores"), \
"industrial" = list("consumer industrial"), \
"jobs" = list("shopkeepers", "assistants", "manual daytime hygiene engineers", "janitors", "chefs", "cooks")
)
/datum/industry/consumer/generateProductName(var/company)
var/list/meat = list("chicken", "lizard", "corgi", "monkey", "goat", "fly", "xenomorph", "human", "walrus", "wendigo", "bear", "clown", "turkey", "pork", "carp", "crab", "mimic", "mystery")
var/list/qualifier = list("synthetic", "organic", "bio", "diet", "sugar-free", "paleolithic", "homeopathic", "recycled", "reclaimed", "vat-grown")
return "the [pick(qualifier)] [pick(meat)] meat product line"
/datum/industry/mining
name = "Mining"
tokens = list( \
"industry" = list("mines", "large scale mining operations"), \
"industrial" = list("resource acquisitional"), \
"jobs" = list("shaft miners", "drill operators", "mining foremen", "gibtonite handlers")
)
/datum/industry/mining/generateProductName(var/company)
var/list/equipment = list("drill", "pickaxe", "shovel", "jackhammer", "mini-pickaxe", "power hammer", "power gloves", "power armor", "hardsuit", "kinetic accelerator", "resonator", "oxygen tank", "emergency bike horn")
var/list/material = list("mauxite", "pharosium", "molitz", "adamantium", "mithril", "cobryl", "bohrum", "claretine", "viscerite", "syreline", "cerenkite", "plasmastone", "gold", "koshmarite", "phoron", "carbon dioxide")
return "the [pick(material)] [pick(equipment)]"
/datum/industry/defense
name = "Defense"
tokens = list ( \
"industry" = list("defense", "warfare", "security", "law enforcement"), \
"industrial" = list("defense"), \
"jobs" = list("security officers", "government officials", "soldiers", "weapons engineers")
)
/datum/industry/defense/generateProductName(var/company)
var/list/equipment = list("energy gun", "laser gun", "machine gun", "grenade", "stun baton", "artillery", "bomb", "attack drone", "missile", "chem sprayer")
var/list/material = list("bluespace", "stealth", "heat-seeking", "crime-seeking", "wide-range", "bioterror", "auto-reloading", "smart", "sentient", "rapid-fire", "species-targeting", "gibtonite", "mass-market", "perpetual-motion", "nuclear", "fission", "fusion")
return "the [pick(material)] [pick(equipment)]"
@@ -0,0 +1,14 @@
/datum/stock_log
var/user_name = ""
var/company_name = ""
var/shareprice
var/money
var/stocks
var/time
/datum/stock_log/buy
/datum/stock_log/sell
/datum/stock_log/borrow
@@ -0,0 +1,170 @@
/datum/stockMarket
var/list/stocks = list()
var/list/balances = list()
var/list/last_read = list()
var/list/stockBrokers = list()
var/list/logs = list()
/datum/stockMarket/New()
..()
generateBrokers()
generateStocks()
START_PROCESSING(SSobj, src)
/datum/stockMarket/proc/balanceLog(var/whose, var/net)
if (!(whose in balances))
balances[whose] = net
else
balances[whose] += net
/datum/stockMarket/proc/generateBrokers()
stockBrokers = list()
var/list/fnames = list("Goldman", "Edward", "James", "Luis", "Alexander", "Walter", "Eugene", "Mary", "Morgan", "Jane", "Elizabeth", "Xavier", "Hayden", "Samuel", "Lee")
var/list/names = list("Johnson", "Rothschild", "Sachs", "Stanley", "Hepburn", "Brown", "McColl", "Fischer", "Edwards", "Becker", "Witter", "Walker", "Lambert", "Smith", "Montgomery", "Lynch", "Roosevelt", "Lehman")
var/list/locations = list("Earth", "Luna", "Mars", "Saturn", "Jupiter", "Uranus", "Pluto", "Europa", "Io", "Phobos", "Deimos", "Space", "Venus", "Neptune", "Mercury", "Kalliope", "Ganymede", "Callisto", "Amalthea", "Himalia", "Sybil", "Basil", "Badger", "Terry", "Artyom")
var/list/first = list("The", "First", "Premier", "Finest", "Prime")
var/list/company = list("Investments", "Securities", "Corporation", "Bank", "Brokerage", "& Co.", "Brothers", "& Sons", "Investement Firm", "Union", "Partners", "Capital", "Trade", "Holdings")
for(var/i in 1 to 5)
var/pname = ""
switch (rand(1,5))
if (1)
pname = "[prob(10) ? pick(first) + " " : null][pick(names)] [pick(company)]"
if (2)
pname = "[pick(names)] & [pick(names)][prob(25) ? " " + pick(company) : null]"
if (3)
pname = "[prob(45) ? pick(first) + " " : null][pick(locations)] [pick(company)]"
if (4)
pname = "[prob(10) ? "The " : null][pick(names)] [pick(locations)] [pick(company)]"
if (5)
pname = "[prob(10) ? "The " : null][pick(fnames)] [pick(names)][prob(10) ? " " + pick(company) : null]"
if (pname in stockBrokers)
i--
continue
stockBrokers += pname
/datum/stockMarket/proc/generateDesignation(var/name)
if (length(name) <= 4)
return uppertext(name)
var/list/split_name = splittext(name, " ")
if (split_name.len >= 2)
var/capitalised_name = ""
for(var/string_index in 1 to min(5, split_name.len))
capitalised_name += uppertext(ascii2text(text2ascii(split_name[string_index], 1)))
return capitalised_name
else
var/capitalised_name = uppertext(ascii2text(text2ascii(name, 1)))
for(var/string_index in 2 to length(name))
if (prob(100 / string_index))
capitalised_name += uppertext(ascii2text(text2ascii(name, string_index)))
return capitalised_name
/datum/stockMarket/proc/generateStocks(var/amt = 15)
var/list/fruits = list("Banana", "Mimana", "Watermelon", "Ambrosia", "Pomegranate", "Reishi", "Papaya", "Mango", "Tomato", "Conkerberry", "Wood", "Lychee", "Mandarin", "Harebell", "Pumpkin", "Rhubarb", "Tamarillo", "Yantok", "Ziziphus", "Oranges", "Daisy", "Kudzu")
var/list/tech_prefix = list("Nano", "Cyber", "Funk", "Astro", "Fusion", "Tera", "Exo", "Star", "Virtual", "Plasma", "Robust", "Bit", "Future", "Hugbox", "Carbon", "Nerf", "Buff", "Nova", "Space", "Meta", "Cyber")
var/list/tech_short = list("soft", "tech", "prog", "tec", "tek", "ware", "", "gadgets", "nics", "tric", "trasen", "tronic", "coin")
var/list/random_nouns = list("Johnson", "Cluwne", "General", "Specific", "Master", "King", "Queen", "Table", "Rupture", "Dynamic", "Massive", "Mega", "Giga", "Certain", "Singulo", "State", "National", "International", "Interplanetary", "Sector", "Planet", "Burn", "Robust", "Exotic", "Solar", "Lunar", "Chelp", "Corgi", "Lag", "Lizard")
var/list/company = list("Company", "Factory", "Incorporated", "Industries", "Group", "Consolidated", "GmbH", "LLC", "Ltd", "Inc.", "Association", "Limited", "Software", "Technology", "Programming", "IT Group", "Electronics", "Nanotechnology", "Farms", "Stores", "Mobile", "Motors", "Electric", "Designs", "Energy", "Pharmaceuticals", "Communications", "Wholesale", "Holding", "Health", "Machines", "Astrotech", "Gadgets", "Kinetics")
for (var/i = 1, i <= amt, i++)
var/datum/stock/new_stock = new
var/sname = ""
switch (rand(1,6))
if(1) // VVVVVVVV this is a check to prevent the word from randomly showing up in game, github dont lynch us
while (sname == "" || sname == "FAG") // honestly it's a 0.6% chance per round this happens - or once in 166 rounds - so i'm accounting for it before someone yells at me
sname = "[consonant()][vowel()][consonant()]"
if (2)
sname = "[pick(tech_prefix)][pick(tech_short)][prob(20) ? " " + pick(company) : null]"
if (3 to 4)
var/fruit = pick(fruits)
fruits -= fruit
sname = "[prob(10) ? "The " : null][fruit][prob(40) ? " " + pick(company): null]"
if (5 to 6)
var/pname = pick(random_nouns)
random_nouns -= pname
switch (rand(1,3))
if (1)
sname = "[pname] & [pname]"
if (2)
sname = "[pname] [pick(company)]"
if (3)
sname = "[pname]"
new_stock.name = sname
new_stock.short_name = generateDesignation(new_stock.name)
new_stock.current_value = rand(10, 125)
var/rate_of_change = rand(10, 40) / 10
new_stock.fluctuational_coefficient = prob(50) ? (1 / rate_of_change) : rate_of_change
new_stock.average_optimism = rand(-10, 10) / 100
new_stock.optimism = new_stock.average_optimism + (rand(-40, 40) / 100)
new_stock.current_trend = rand(-200, 200) / 10
new_stock.last_trend = new_stock.current_trend
new_stock.disp_value_change = rand(-1, 1)
new_stock.speculation = rand(-20, 20)
new_stock.average_shares = round(rand(500, 10000) / 10)
new_stock.outside_shareholders = rand(1000, 30000)
new_stock.available_shares = rand(200000, 800000)
new_stock.fluctuation_rate = rand(6, 20)
new_stock.generateIndustry()
new_stock.generateEvents()
stocks += new_stock
last_read[new_stock] = list()
/datum/stockMarket/process()
for (var/stock in stocks)
var/datum/stock/current_stock = stock
current_stock.process()
/datum/stockMarket/proc/add_log(var/log_type, var/user, var/company_name, var/stocks, var/shareprice, var/money)
var/datum/stock_log/new_stock_log = new log_type
new_stock_log.user_name = user
new_stock_log.company_name = company_name
new_stock_log.stocks = stocks
new_stock_log.shareprice = shareprice
new_stock_log.money = money
new_stock_log.time = time2text(world.timeofday, "hh:mm")
logs += new_stock_log
GLOBAL_DATUM_INIT(stockExchange, /datum/stockMarket, new)
/proc/plotBarGraph(var/list/points, var/base_text, var/width=400, var/height=400)
var/output = "<HTML><HEAD><meta charset='UTF-8'></HEAD><BODY><table style='border:1px solid black; border-collapse: collapse; width: [width]px; height: [height]px'>"
if (points.len && height > 20 && width > 20)
var/min = points[1]
var/max = points[1]
for (var/data_point in points)
if (data_point < min)
min = data_point
if (data_point > max)
max = data_point
var/cells = (height - 20) / 20
if (cells > round(cells))
cells = round(cells) + 1
var/diff = max - min
var/ost = diff / cells
if (min > 0)
min = max(min - ost, 0)
diff = max - min
ost = diff / cells
var/cval = max
var/cwid = width / (points.len + 1)
for (var/y_axis = cells, y_axis > 0, y_axis--)
if (y_axis == cells)
output += "<tr>"
else
output += "<tr style='border:none; border-top:1px solid #00ff00; height: 20px'>"
for (var/x_axis = 0, x_axis <= points.len, x_axis++)
if (x_axis == 0)
output += "<td style='border:none; height: 20px; width: [cwid]px; font-size:10px; color:#00ff00; background:black; text-align:right; vertical-align:bottom'>[round(cval - ost)]</td>"
else
var/data_point = points[x_axis]
if (data_point >= cval)
output += "<td style='border:none; height: 20px; width: [cwid]px; background:#0000ff'>&nbsp;</td>"
else
output += "<td style='border:none; height: 20px; width: [cwid]px; background:black'>&nbsp;</td>"
output += "</tr>"
cval -= ost
output += "<tr><td style='font-size:10px; height: 20px; width: 100%; background:black; color:green; text-align:center' colspan='[points.len + 1]'>[base_text]</td></tr>"
else
output += "<tr><td style='width:[width]px; height:[height]px; background: black'></td></tr>"
output += "<tr><td style='font-size:10px; background:black; color:green; text-align:center'>[base_text]</td></tr>"
return "[output]</table></BODY></HTML>"
@@ -0,0 +1,316 @@
/datum/borrow
var/broker = ""
var/borrower = ""
var/datum/stock/stock = null
var/lease_expires = 0
var/lease_time = 0
var/grace_time = 0
var/grace_expires = 0
var/share_amount = 0
var/share_debt = 0
var/deposit = 0
var/offer_expires = 0
/datum/stock
var/name = "Stock"
var/short_name = "STK"
var/desc = "A company that does not exist."
var/list/values = list()
var/current_value = 10
var/value_cap = 450000
var/last_value = 10
var/list/products = list()
var/performance = 0 // The current performance of the company. Tends itself to 0 when no events happen.
// These variables determine standard fluctuational patterns for this stock.
var/fluctuational_coefficient = 1 // How much the price fluctuates on an average daily basis
var/average_optimism = 0 // The history of shareholder optimism of this stock
var/current_trend = 0
var/last_trend = 0
var/speculation = 0
var/bankrupt = 0
var/disp_value_change = 0
var/optimism = 0
var/last_unification = 0
var/average_shares = 100
var/outside_shareholders = 10000 // The amount of offstation people holding shares in this company. The higher it is, the more fluctuation it causes.
var/available_shares = 500000
var/list/borrow_brokers = list()
var/list/shareholders = list()
var/list/borrows = list()
var/list/events = list()
var/list/articles = list()
var/fluctuation_rate = 15
var/fluctuation_counter = 0
var/datum/industry/industry = null
/datum/stock/proc/addEvent(var/datum/stockEvent/stock_event)
events |= stock_event
/datum/stock/proc/addArticle(var/datum/article/stock_article)
if (!(stock_article in articles))
articles.Insert(1, stock_article)
stock_article.ticks = world.time
/datum/stock/proc/generateEvents()
var/list/types = typesof(/datum/stockEvent) - /datum/stockEvent
for (var/stock_type in types)
generateEvent(stock_type)
/datum/stock/proc/generateEvent(var/event_type)
var/datum/stockEvent/stock_event = new event_type(src)
addEvent(stock_event)
/datum/stock/proc/affectPublicOpinion(var/boost)
optimism += rand(0, 500) / 500 * boost
average_optimism += rand(0, 150) / 5000 * boost
speculation += rand(-1, 50) / 10 * boost
performance += rand(0, 150) / 100 * boost
/datum/stock/proc/generateIndustry()
if (findtext(name, "Farms"))
industry = new /datum/industry/agriculture
else if (findtext(name, "Software") || findtext(name, "Programming") || findtext(name, "IT Group") || findtext(name, "Electronics") || findtext(name, "Electric") || findtext(name, "Nanotechnology"))
industry = new /datum/industry/it
else if (findtext(name, "Mobile") || findtext(name, "Communications"))
industry = new /datum/industry/communications
else if (findtext(name, "Pharmaceuticals") || findtext(name, "Health"))
industry = new /datum/industry/health
else if (findtext(name, "Wholesale") || findtext(name, "Stores"))
industry = new /datum/industry/consumer
else
var/ts = typesof(/datum/industry) - /datum/industry
var/in_t = pick(ts)
industry = new in_t
for (var/i = 0, i < rand(2, 5), i++)
products += industry.generateProductName(name)
/datum/stock/proc/frc(amt)
var/shares = available_shares + outside_shareholders * average_shares
var/fr = amt / 100 / shares * fluctuational_coefficient * fluctuation_rate * max(-(current_trend / 100), 1)
if ((fr < 0 && speculation < 0) || (fr > 0 && speculation > 0))
fr *= max(abs(speculation) / 5, 1)
else
fr /= max(abs(speculation) / 5, 1)
return fr
/datum/stock/proc/supplyGrowth(amt)
var/fr = frc(amt)
available_shares += amt
if (abs(fr) < 0.0001)
return
current_value -= fr * current_value
/datum/stock/proc/supplyDrop(amt)
supplyGrowth(-amt)
/datum/stock/proc/fluctuate()
var/change = rand(-100, 100) / 10 + optimism * rand(200) / 10
optimism -= (optimism - average_optimism) * (rand(10,80) / 1000)
var/shift_score = change + current_trend
var/as_score = abs(shift_score)
var/sh_change_dev = rand(-10, 10) / 10
var/sh_change = shift_score / (as_score + 100) + sh_change_dev
var/shareholder_change = round(sh_change)
outside_shareholders += shareholder_change
var/share_change = shareholder_change * average_shares
if (as_score > 20 && prob(as_score / 4))
var/avg_change_dev = rand(-10, 10) / 10
var/avg_change = shift_score / (as_score + 100) + avg_change_dev
average_shares += avg_change
share_change += outside_shareholders * avg_change
var/cv = last_value
supplyDrop(share_change)
available_shares += share_change // temporary
if (prob(25))
average_optimism = max(min(average_optimism + (rand(-3, 3) - current_trend * 0.15) / 100, 1), -1)
var/aspec = abs(speculation)
if (prob((aspec - 75) * 2))
speculation += rand(-4, 4)
else
if (prob(50))
speculation += rand(-4, 4)
else
speculation += rand(-400, 0) / 1000 * speculation
if (prob(1) && prob(5)) // pop that bubble
speculation += rand(-4000, 0) / 1000 * speculation
var/fucking_stock_spikes = current_value + 500
var/piece_of_shit_fuck = current_value - 500
var/i_hate_this_code = (speculation / rand(25000, 50000) + performance / rand(100, 800)) * current_value
if(i_hate_this_code < fucking_stock_spikes || i_hate_this_code > piece_of_shit_fuck)
current_value += i_hate_this_code
if(current_value > value_cap)
current_value = 450000
if (current_value < 5)
current_value = 5
if (performance != 0)
performance = rand(900,1050) / 1000 * performance
if (abs(performance) < 0.2)
performance = 0
disp_value_change = (cv < current_value) ? 1 : ((cv > current_value) ? -1 : 0)
last_value = current_value
if (values.len >= 50)
values.Cut(1,2)
values += current_value
if (current_value < 10)
unifyShares()
last_trend = current_trend
current_trend += rand(-200, 200) / 100 + optimism * rand(200) / 10 + max(50 - abs(speculation), 0) / 50 * rand(0, 200) / 1000 * (-current_trend) + max(speculation - 50, 0) * rand(0, 200) / 1000 * speculation / 400
/datum/stock/proc/unifyShares()
for (var/shareholder in shareholders)
var/shr = shareholders[shareholder]
if (shr % 2)
sellShares(shareholder, 1)
shr -= 1
shareholders[shareholder] /= 2
if (!shareholders[shareholder])
shareholders -= shareholder
for (var/datum/borrow/broker in borrow_brokers)
broker.share_amount = round(broker.share_amount / 2)
broker.share_debt = round(broker.share_debt / 2)
for (var/datum/borrow/borrower in borrows)
borrower.share_amount = round(borrower.share_amount / 2)
borrower.share_debt = round(borrower.share_debt / 2)
average_shares /= 2
available_shares /= 2
current_value *= 2
last_unification = world.time
/datum/stock/process()
for (var/borrower in borrows)
var/datum/borrow/borrow = borrower
if (world.time > borrow.grace_expires)
modifyAccount(borrow.borrower, -max(current_value * borrow.share_debt, 0), 1)
borrows -= borrow
if (borrow.borrower in GLOB.FrozenAccounts)
GLOB.FrozenAccounts[borrow.borrower] -= borrow
if (length(GLOB.FrozenAccounts[borrow.borrower]) == 0)
GLOB.FrozenAccounts -= borrow.borrower
qdel(borrow)
else if (world.time > borrow.lease_expires)
if (borrow.borrower in shareholders)
var/amt = shareholders[borrow.borrower]
if (amt > borrow.share_debt)
shareholders[borrow.borrower] -= borrow.share_debt
borrows -= borrow
if (borrow.borrower in GLOB.FrozenAccounts)
GLOB.FrozenAccounts[borrow.borrower] -= borrow
if (length(GLOB.FrozenAccounts[borrow.borrower]) == 0)
GLOB.FrozenAccounts -= borrow.borrower
qdel(borrow)
else
shareholders -= borrow.borrower
borrow.share_debt -= amt
if (bankrupt)
return
for (var/broker in borrow_brokers)
var/datum/borrow/borrow = broker
if (borrow.offer_expires < world.time)
borrow_brokers -= borrow
qdel(borrow)
if (prob(5))
generateBrokers()
fluctuation_counter++
if (fluctuation_counter >= fluctuation_rate)
for (var/stock_event in events)
var/datum/stockEvent/current_stock_event = stock_event
current_stock_event.process()
fluctuation_counter = 0
fluctuate()
/datum/stock/proc/generateBrokers()
if (borrow_brokers.len > 2)
return
if (!GLOB.stockExchange.stockBrokers.len)
GLOB.stockExchange.generateBrokers()
var/broker = pick(GLOB.stockExchange.stockBrokers)
var/datum/borrow/new_borrow = new
new_borrow.broker = broker
new_borrow.stock = src
new_borrow.lease_time = rand(4, 7) * 600
new_borrow.grace_time = rand(1, 3) * 600
new_borrow.share_amount = rand(1, 10) * 100
new_borrow.deposit = rand(20, 70) / 100
new_borrow.share_debt = new_borrow.share_amount
new_borrow.offer_expires = rand(5, 10) * 600 + world.time
borrow_brokers += new_borrow
/datum/stock/proc/modifyAccount(whose, by, force=0)
var/datum/bank_account/dept_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if (dept_account.account_balance)
if (by < 0 && dept_account.account_balance + by < 0 && !force)
return 0
dept_account.account_balance += by
GLOB.stockExchange.balanceLog(whose, by)
return 1
return 0
/datum/stock/proc/borrow(var/datum/borrow/borrow_event, var/who)
if (borrow_event.lease_expires)
return 0
borrow_event.lease_expires = world.time + borrow_event.lease_time
var/old_d = borrow_event.deposit
var/d_amt = borrow_event.deposit * current_value * borrow_event.share_amount
if (!modifyAccount(who, -d_amt))
borrow_event.lease_expires = 0
borrow_event.deposit = old_d
return 0
borrow_event.deposit = d_amt
if (!(who in shareholders))
shareholders[who] = borrow_event.share_amount
else
shareholders[who] += borrow_event.share_amount
borrow_brokers -= borrow_event
borrows += borrow_event
borrow_event.borrower = who
borrow_event.grace_expires = borrow_event.lease_expires + borrow_event.grace_time
if (!(who in GLOB.FrozenAccounts))
GLOB.FrozenAccounts[who] = list(borrow_event)
else
GLOB.FrozenAccounts[who] += borrow_event
return 1
/datum/stock/proc/buyShares(var/who, var/howmany)
if (howmany <= 0)
return
howmany = round(howmany)
var/loss = howmany * current_value
if (available_shares < howmany)
return 0
if (modifyAccount(who, -loss))
supplyDrop(howmany)
if (!(who in shareholders))
shareholders[who] = howmany
else
shareholders[who] += howmany
return 1
return 0
/datum/stock/proc/sellShares(var/whose, var/howmany)
if (howmany < 0)
return
howmany = round(howmany)
var/gain = howmany * current_value
if (shareholders[whose] < howmany)
return 0
if (modifyAccount(whose, gain))
supplyGrowth(howmany)
shareholders[whose] -= howmany
if (shareholders[whose] <= 0)
shareholders -= whose
return 1
return 0
/datum/stock/proc/displayValues(var/mob/user)
user << browse(plotBarGraph(values, "[name] share value per share"), "window=stock_[name];size=450x450")
+8
View File
@@ -4263,6 +4263,14 @@
#include "modular_skyrat\modules\specborg\code\game\objects\items\cyborg_items.dm"
#include "modular_skyrat\modules\specborg\code\modules\living\sillicon\robot\robot_module.dm"
#include "modular_skyrat\modules\ssd_indicator\code\mob.dm"
#include "modular_skyrat\modules\stock_market\code\articles.dm"
#include "modular_skyrat\modules\stock_market\code\computer.dm"
#include "modular_skyrat\modules\stock_market\code\computer_circuitboards.dm"
#include "modular_skyrat\modules\stock_market\code\events.dm"
#include "modular_skyrat\modules\stock_market\code\industries.dm"
#include "modular_skyrat\modules\stock_market\code\logs.dm"
#include "modular_skyrat\modules\stock_market\code\stockmarket.dm"
#include "modular_skyrat\modules\stock_market\code\stocks.dm"
#include "modular_skyrat\modules\stormtrooper\code\stormtrooper_clothes.dm"
#include "modular_skyrat\modules\tableflip\code\flipped_table.dm"
#include "modular_skyrat\modules\tagline\code\world.dm"