/obj/npc/station_trader //separate obj because he has a lot of different behaviours eg. no buying, no set area, no defence systems to activate
name="Shady Robot"
icon = 'icons/misc/evilreaverstation.dmi' //temporary
icon_state = "pr1_b"
picture = "robot.png"
var/hiketolerance = 20 //How much they will tolerate price hike
var/list/droplist = null //What the merchant will drop upon their death
var/list/goods_sell = new/list() //What products the trader sells
var/list/shopping_cart = new/list() //What has been bought
var/obj/item/sell = null //Item to sell
var/portrait_setup = null
var/obj/item/sellitem = null
var/item_name = "--------"
var/obj/item/card/id/scan = null
//Trader dialogue
var/buy_dialogue = null
var/list/successful_sale_dialogue = null
var/list/failed_sale_dialogue = null
var/list/successful_purchase_dialogue = null
var/list/failed_purchase_dialogue = null
var/pickupdialogue = null
var/pickupdialoguefailure = null
var/list/trader_areas = list(/area/station/maintenance/southsolar,/area/station/solar/south,/area/station/maintenance/east,/area/station/maintenance/SEmaint,/area/station/maintenance/eastsolar,/area/station/solar/east,/area/station/maintenance/south,/area/station/maintenance/disposal,/area/station/maintenance/SWmaint,/area/station/maintenance/westsolar,/area/station/solar/west,/area/station/hallway/secondary/construction,/area/station/maintenance/NWmaint,/area/station/crew_quarters/quartersA,/area/station/crew_quarters/quartersB,/area/station/crew_quarters/observatory,/area/station/wreckage,/area/station/maintenance/north,/area/station/maintenance/maintcentral)
var/doing_a_thing = 0
// This list is in a specific order!!
// String 1 - player is being dumb and hiked a price up when buying, trader accepted it because they're a dick
// String 2 - same as above only the trader is being nice about it
// String 3 - player haggled further than the trader is willing to tolerate
// String 4 - trader has had enough of your bullshit and is leaving
var/list/errormsgs = list("...huh. If you say so!",
"Huh? You want to pay more for my wares than i'm offering?",
"What the f... umm, no? Make me a serious offer.",
"Sorry, you're terrible at this. I must be going.")
// Next list - the last entry will always be used on the trader's final haggling offer
// otherwise the trader picks randomly from the list including the "final offer" in order to bluff players
var/list/hagglemsgs = list("Alright, how's this sound?",
"You drive a hard bargain. How's this price?",
"You're busting my balls here. How's this?",
"I'm being more than generous here, I think you'll agree.",
"This is my final offer. Can't do better than this.")
//CARD VARS
var/card_registered = null //who is the card registered to?
var/card_assignment = null //what job does it have?
var/card_icon_state = "id" //which icon should we use?
var/card_icon_price = 0 //how much does that icon cost (flat price)?
var/card_duration = 60 //how long will the card's access last?
var/list/card_access = list() //what access will it have?
var/card_price = 0 //total card price (calculated when updatecardprice() is called)
var/card_timer = 0 //does the card display time remaining before its access runs out (costs 1000)?
//ACCESS LISTS FOR PRICING & SORTING
var/list/civilian_access_list = list(6, 12, 22, 23, 25, 26, 27, 28, 35, 36)
var/list/engineering_access_list = list(13, 32, 40, 43, 44, 45, 46, 47, 48)
var/list/supply_access_list = list(30, 31, 34, 47, 50, 51)
var/list/research_access_list = list(5, 7, 8, 9, 10, 24, 29, 33)
var/list/security_access_list = list(1, 2, 3, 4, 37, 38, 39)
var/list/command_access_list = list(11, 14, 15, 16, 17, 18, 19, 20, 21, 49, 53)
var/list/special_access_list = list(37)
//PRODUCTS
var/list/common_products = list(/datum/commodity/bodyparts/butt,/datum/commodity/contraband/ntso_uniform,/datum/commodity/contraband/ntso_vest,/datum/commodity/contraband/ntso_beret,/datum/commodity/drugs/methamphetamine,/datum/commodity/drugs/crank,/datum/commodity/drugs/catdrugs,/datum/commodity/drugs/morphine,/datum/commodity/drugs/krokodil,/datum/commodity/drugs/lsd,/datum/commodity/drugs/shrooms,/datum/commodity/drugs/cannabis,/datum/commodity/drugs/cannabis_mega,/datum/commodity/drugs/cannabis_white,/datum/commodity/drugs/cannabis_omega,/datum/commodity/produce/special/ghostchili,/datum/commodity/contraband/secheadset,/datum/commodity/medical/strange_reagent,/datum/commodity/drugs/cyberpunk,/datum/commodity/contraband/swatmask,/datum/commodity/contraband/briefcase,/datum/commodity/bodyparts/heart,/datum/commodity/bodyparts/eye)
var/num_common_products = 13 //how many of these to pick for sale
var/list/rare_products = list(/datum/commodity/contraband/radiojammer,/datum/commodity/contraband/stealthstorage,/datum/commodity/medical/injectorbelt,/datum/commodity/medical/injectormask,/datum/commodity/junk/voltron,/datum/commodity/laser_gun,/datum/commodity/relics/crown,/datum/commodity/contraband/egun,/datum/commodity/relics/armor,/datum/commodity/contraband/spareid,/datum/commodity/contraband/voicechanger,/datum/commodity/contraband/chamsuit,/datum/commodity/contraband/dnascram)
var/num_rare_products = 2 //how many of these to pick for sale
New()
..()
teleport()
process()
for(var/i = 1 to num_common_products)
var/datum/commodity/C = pick(common_products)
goods_sell += new C(src)
common_products -= C //so we don't get duplicates
for(var/i = 1 to num_rare_products)
var/datum/commodity/C = pick(rare_products)
goods_sell += new C(src)
rare_products -= C //so we don't get duplicates
proc/process()
spawn(300)
if(prob(20) && !scan)
teleport()
process()
anger()
for(var/mob/M in AIviewers(src))
boutput(M, "[src.name] becomes angry!")
src.desc = "[src] looks angry."
teleport()
spawn(rand(1000,3000))
src.visible_message("[src.name] calms down.")
src.desc = "[src] looks a bit annoyed."
src.temp = "[src.name] has calmed down.
OK"
src.angry = 0
return
proc/teleport()
var/area/A = pick(trader_areas)
var/turf/target = null
var/list/locs = list()
for(var/turf/T in A)
var/dense = 0
if(T.density)
dense = 1
else
for(var/obj/O in T)
if(O.density)
dense = 1
break
if(dense == 0) locs += T
if(!locs.len) return
target = pick(locs)
showswirl(src.loc)
src.loc = target
showswirl(target)
//reset stuff to default
card_registered = null
card_assignment = null
card_icon_state = "id"
card_icon_price = 0
card_duration = 60
card_access = list()
card_price = 0
card_timer = 0
return
attack_hand(var/mob/user as mob)
if(..())
return
if(angry)
boutput(user, "[src] is angry and won't trade with anyone right now.")
return
user.machine = src
var/dat = updatemenu()
if(!temp)
dat += {"[src.greeting]
Purchase Temporary ID
Purchase Items
View Cart
I'm Ready to Pick Up My Order
Goodbye"}
user << browse(dat, "window=trader;size=575x530")
onclose(user, "trader")
return
disposing()
goods_sell = null
shopping_cart = null
..()
Topic(href, href_list)
if(..())
return
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
usr.machine = src
///////////////////////////////
///////Generate Purchase List//
///////////////////////////////
if (href_list["temp_card"])
src.temp = "I can hook you up with a temporary ID, just let me know what you need.
"
src.temp = "Price: [card_price] credits
"
src.temp += "Registered: [card_registered ? card_registered : "--------"]
"
src.temp += "Assignment: [card_assignment ? card_assignment : "--------"]
"
src.temp += "Duration: [card_duration ? card_duration : "--------"] seconds
"
if(card_timer)
src.temp += "Timer (1000 credits): Yes/No
"
else
src.temp += "Timer (1000 credits): Yes/No
"
//Change access to individual areas
src.temp += "
Access"
src.temp += "
Prices are per second."
//Organised into sections
var/civilian_access = "
Staff (1):"
var/engineering_access = "
Engineering (2):"
/* Conor12: I removed some unused accesses as the page is large enough, add these if they ever get used:
41 (access_engineering_storage)
42 (access_engineering_eva)*/
var/supply_access = "
Supply (2):"
var/research_access = "
Science and Medical (5):"
var/security_access = "
Security (10):"
var/command_access = "
Command (10):"
var/special_access = "
Special (50):"
for(var/A in access_name_lookup)
if(access_name_lookup[A] in src.card_access)
//Click these to remove access
if (access_name_lookup[A] in civilian_access_list)
civilian_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in engineering_access_list)
engineering_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in supply_access_list)
supply_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in research_access_list)
research_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in security_access_list)
security_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in command_access_list)
command_access += " [replacetext(A, " ", " ")]"
else//Click these to add access
if (access_name_lookup[A] in civilian_access_list)
civilian_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in engineering_access_list)
engineering_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in supply_access_list)
supply_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in research_access_list)
research_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in security_access_list)
security_access += " [replacetext(A, " ", " ")]"
if (access_name_lookup[A] in command_access_list)
command_access += " [replacetext(A, " ", " ")]"
if(37 in src.card_access)
special_access += " Head of Security"
else
special_access += " Head of Security"
src.temp += "[civilian_access][engineering_access][supply_access][research_access][security_access][command_access][special_access]"
src.temp += "
Customise ID
"
src.temp += "[src.card_icon_state == "id" ? "" : ""]Plain[src.card_icon_state == "id" ? " " : " "]"
src.temp += "[src.card_icon_state == "id_civ" ? "" : ""]Civilian[src.card_icon_state == "id_civ" ? " " : " "]"
src.temp += "[src.card_icon_state == "id_clown" ? "" : ""]Clown[src.card_icon_state == "id_clown" ? " " : " "]"
src.temp += "[src.card_icon_state == "id_eng" ? "" : ""]Engineering[src.card_icon_state == "id_eng" ? " " : " "]"
src.temp += "[src.card_icon_state == "id_res" ? "" : ""]Research[src.card_icon_state == "id_res" ? " " : " "]"
src.temp += "[src.card_icon_state == "id_sec" ? "" : ""]Security[src.card_icon_state == "id_sec" ? " " : " "]"
src.temp += "[src.card_icon_state == "id_com" ? "" : ""]Command[src.card_icon_state == "id_com" ? " " : " "]"
src.temp += "[src.card_icon_state == "gold" ? "" : ""]Captain[src.card_icon_state == "gold" ? "" : ""]"
src.temp += "
Purchase"
src.temp += "
Back"
if (href_list["access"] && href_list["allowed"])
var/access_type = text2num(href_list["access"])
var/access_allowed = text2num(href_list["allowed"])
if(access_type == 37)
src.card_access -= access_type
if(access_allowed == 1)
src.card_access += access_type
else if(access_type in get_all_accesses())
src.card_access -= access_type
if(access_allowed == 1)
src.card_access += access_type
updatecardprice()
href = "temp_card=1"
src.Topic(href, params2list(href))
if(href_list["timer"])
src.card_timer = text2num(href_list["timer"])
updatecardprice()
href = "temp_card=1"
src.Topic(href, params2list(href))
if (href_list["colour"])
var/newcolour = href_list["colour"]
switch(newcolour)
if ("none")
src.card_icon_state = "id"
src.card_icon_price = 0
if ("blue")
src.card_icon_state = "id_civ"
src.card_icon_price = 0
if ("clown")
src.card_icon_state = "id_clown"
src.card_icon_price = 0
if ("yellow")
src.card_icon_state = "id_eng"
src.card_icon_price = 500
if ("purple")
src.card_icon_state = "id_res"
src.card_icon_price = 500
if ("red")
src.card_icon_state = "id_sec"
src.card_icon_price = 1000
if ("green")
src.card_icon_state = "id_com"
src.card_icon_price = 2000
if ("gold")
src.card_icon_state = "gold"
src.card_icon_price = 5000
updatecardprice()
href = "temp_card=1"
src.Topic(href, params2list(href))
if (href_list["registered"])
src.card_registered = input("Registered name?","Temporary ID")
href = "temp_card=1"
src.Topic(href, params2list(href))
if (href_list["assignment"])
src.card_assignment = input("Job title?","Temporary ID")
href = "temp_card=1"
src.Topic(href, params2list(href))
if (href_list["duration"])
var/input = input("Duration in seconds (1-600)?","Temporary ID") as num
if(isnum(input))
src.card_duration = min(max(input,1),600)
updatecardprice()
href = "temp_card=1"
src.Topic(href, params2list(href))
if (href_list["buycard"])
if(!scan)
src.temp = {"You have to scan a card in first.
OK"}
src.updateUsrDialog()
return
updatecardprice() //should be updated but just to be sure
var/datum/data/record/account = null
account = FindBankAccountByName(src.scan.registered)
if(!account)
src.temp = {"That's odd I can't seem to find your account
OK"}
else if(account.fields["current_money"] < src.card_price)
src.temp = {"Sorry [pick("buddy","pal","mate","friend","chief","bud","boss","champ")], you can't afford that!
OK"}
else
if(spawncard())
account.fields["current_money"] -= src.card_price
src.temp = {"There ya go. You've got [src.card_duration] seconds to abuse that thing before its access is revoked.
OK"}
//reset to default so people can't go snooping and find out the last ordered card
card_registered = null
card_assignment = null
card_icon_state = "id"
card_icon_price = 0
card_duration = 60
card_access = list()
card_price = 0
card_timer = 0
if (href_list["purchase"])
src.temp =buy_dialogue + "
"
for(var/datum/commodity/N in goods_sell)
// Have to send the type instead of a reference to the obj because it would get caught by the garbage collector. oh well.
src.temp += {"[N.comname]
Cost: [N.price] Credits
Description: [N.desc]
Haggle
"}
src.temp += "
Ok"
//////////////////////////////////////////////
///////Handle the buying of a specific item //
//////////////////////////////////////////////
else if (href_list["doorder"])
if(!scan)
src.temp = {"You have to scan a card in first.
OK"}
src.updateUsrDialog()
return
if (src.scan.registered in FrozenAccounts)
boutput(usr, "Your account cannot currently be liquidated due to active borrows.")
return
var/datum/data/record/account = null
account = FindBankAccountByName(src.scan.registered)
if (account)
var/quantity = 1
quantity = input("How many units do you want to purchase? Maximum: 10", "Trader Purchase", null, null) as num
if (quantity < 1)
quantity = 0
return
else if (quantity >= 10)
quantity = 10
////////////
var/datum/commodity/P = locate(href_list["doorder"])
if(P)
if(account.fields["current_money"] >= P.price * quantity)
account.fields["current_money"] -= P.price * quantity
while(quantity-- > 0)
shopping_cart += new P.comtype()
src.temp = {"[pick(successful_purchase_dialogue)]
What other things have you got for sale?
I want to pick up my order.
I've got some other business."}
else
src.temp = {"[pick(failed_purchase_dialogue)]
OK"}
else
src.temp = {"[src] looks bewildered for a second. Seems like they can't find your item.
OK"}
else
src.temp = {"That's odd I can't seem to find your account
OK"}
///////////////////////////////////////////
///Handles haggling for buying ////////////
///////////////////////////////////////////
else if (href_list["haggleb"])
var/askingprice= input(usr, "Please enter your asking price.", "Haggle", 0) as null|num
if(askingprice)
var/datum/commodity/N = locate(href_list["haggleb"])
if(N)
if(patience == N.haggleattempts)
src.temp = "[src.name] becomes angry and won't trade anymore."
src.add_fingerprint(usr)
src.updateUsrDialog()
angry = 1
anger()
else
haggle(askingprice, 1, N)
src.temp +="
Ok"
///////////////////////////////////
////////Handle Bank account Set-Up ///////
//////////////////////////////////
else if (href_list["card"])
if (src.scan) src.scan = null
else
var/obj/item/I = usr.equipped()
if (istype(I, /obj/item/card/id))
boutput(usr, "You swipe the ID card in the card reader.")
var/datum/data/record/account = null
account = FindBankAccountByName(I:registered)
if(account)
var/enterpin = input(usr, "Please enter your PIN number.", "Card Reader", 0) as null|num
if (enterpin == I:pin)
boutput(usr, "Card authorized.")
src.scan = I
else
boutput(usr, "Pin number incorrect.")
src.scan = null
else
boutput(usr, "No bank account associated with this ID found.")
src.scan = null
////////////////////////////////////////////////////
//////View what still needs to be picked up/////////
///////////////////////////////////////////////////
else if (href_list["viewcart"])
src.temp = "Current Items in Cart: "
for(var/obj/S in shopping_cart)
temp+= "
[S.name]"
src.temp += "
OK"
////////////////////////////////////////////////////
/////Pick up the goods ordered from merchant////////
//////////////////////////////////////////////////////
else if (href_list["pickuporder"])
if(shopping_cart.len)
spawncrate()
src.temp = pickupdialogue
else
src.temp = pickupdialoguefailure
src.temp += "
OK"
else if (href_list["mainmenu"])
src.temp = null
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/////////////////////////////////////////////
/////Update the menu with the default items
////////////////////////////////////////////
proc/updatemenu()
var/dat
dat = portrait_setup
dat +="Scanned Card: ([src.scan])
"
if(scan)
var/datum/data/record/account = null
account = FindBankAccountByName(src.scan.registered)
if (account)
dat+="Current Funds: [account.fields["current_money"]] Credits
"
else
dat+="
"
else
dat+="
"
if(temp)
dat+=temp
return dat
/////////////////////////////////////////////
/////Update card price
////////////////////////////////////////////
proc/updatecardprice()
var/access_price = 0
for(var/access in card_access)
if(access in civilian_access_list)
access_price += 1
else if(access in engineering_access_list)
access_price += 2
else if(access in supply_access_list)
access_price += 2
else if(access in research_access_list)
access_price += 5
else if(access in security_access_list)
access_price += 10
else if(access in command_access_list)
access_price += 10
else if(access in special_access_list)
access_price += 50
src.card_price = src.card_icon_price + 1000*card_timer + src.card_duration*access_price
////////////////////////////////////////
/////// Spawn the crate or card ////////
////////////////////////////////////////
proc/spawncrate()
var/turf/pickedloc = get_step(src.loc,src.dir)
if(!pickedloc || pickedloc.density)
var/list/locs = list()
for(var/turf/T in view(1,src))
var/dense = 0
if(T.density)
dense = 1
else
for(var/obj/O in T)
if(O.density)
dense = 1
break
if(dense == 0) locs += T
pickedloc = pick(locs)
if(!pickedloc)
src.visible_message("[src.name] glances around as if confused, then shrugs.")
teleport()
return
var/atom/A = new /obj/storage/crate(pickedloc)
showswirl(pickedloc)
A.name = "Goods Crate ([src.name])"
for(var/obj/O in shopping_cart)
O.set_loc(A)
shopping_cart = new/list()
proc/spawncard()
var/turf/pickedloc = get_step(src.loc,src.dir)
if(!pickedloc || pickedloc.density)
var/list/locs = list()
for(var/turf/T in view(1,src))
var/dense = 0
if(T.density)
dense = 1
else
for(var/obj/O in T)
if(O.density)
dense = 1
break
if(dense == 0) locs += T
pickedloc = pick(locs)
if(!pickedloc)
src.visible_message("[src.name] glances around as if confused, then shrugs.")
teleport()
return 0
var/obj/item/card/id/temporary/I = new /obj/item/card/id/temporary(pickedloc)
showswirl(pickedloc)
I.name = "[src.card_registered]'s ID Card ([src.card_assignment])"
I.registered = card_registered
I.assignment = card_assignment
I.icon_state = card_icon_state
I.duration = card_duration
I.access = card_access
I.timer = card_timer
return 1
////////////////////////////////////////////////////
/////////Proc for haggling with dealer ////////////
///////////////////////////////////////////////////
proc/haggle(var/askingprice, var/buying, var/datum/commodity/H)
// if something's gone wrong and there's no input, reject the haggle
// also reject if there's no change in the price at all
if (!askingprice) return
if (askingprice == H.price) return
// if the player is being dumb and haggling in the wrong direction, tell them (unless the trader is an asshole)
// we're buying, so we want to pay less per unit
if(askingprice > H.price)
src.temp = src.errormsgs[2]
return
// check if the price increase % of the haggle is more than this trader will tolerate
var/hikeperc = askingprice - H.price
hikeperc = (hikeperc / H.price) * 100
var/negatol = 0 - src.hiketolerance
if (hikeperc <= negatol)
src.temp = "Cost: [H.price] Credits
"
src.temp += src.errormsgs[3]
H.haggleattempts++
return
// now, the actual haggling part! find the middle ground between the two prices
var/middleground = (H.price + askingprice) / 2
var/negotiate = abs(H.price-middleground)-1
H.price =round(middleground + rand(0,negotiate))
src.temp = "New Cost: [H.price] Credits
"
H.haggleattempts++
// warn the player if the trader isn't going to take any more haggling
if (patience == H.haggleattempts)
src.temp += src.hagglemsgs[src.hagglemsgs.len]
else
src.temp += pick(src.hagglemsgs)