This repository has been archived by the owner on Sep 12, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 66
/
exports.dm
199 lines (164 loc) · 7.47 KB
/
exports.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* How it works:
The shuttle arrives at CentCom dock and calls sell(), which recursively loops through all the shuttle contents that are unanchored.
Each object in the loop is checked for applies_to() of various export datums, except the invalid ones.
*/
/* The rule in figuring out item export cost:
Export cost of goods in the shipping crate must be always equal or lower than:
packcage cost - crate cost - manifest cost
Crate cost is 500cr for a regular plasteel crate and 100cr for a large wooden one. Manifest cost is always 200cr.
This is to avoid easy cargo points dupes.
Credit dupes that require a lot of manual work shouldn't be removed, unless they yield too much profit for too little work.
For example, if some player buys metal and glass sheets and uses them to make and sell reinforced glass:
100 glass + 50 metal -> 100 reinforced glass
(1500cr -> 1600cr)
then the player gets the profit from selling his own wasted time.
*/
// Simple holder datum to pass export results around
/datum/export_report
var/list/exported_atoms = list() //names of atoms sold/deleted by export
var/list/total_amount = list() //export instance => total count of sold objects of its type, only exists if any were sold
var/list/total_value = list() //export instance => total value of sold objects
var/list/exported_atoms_ref = list() //if they're not deleted they go in here for use.
// external_report works as "transaction" object, pass same one in if you're doing more than one export in single go
/proc/export_item_and_contents(atom/movable/AM, allowed_categories = EXPORT_CARGO, apply_elastic = TRUE, delete_unsold = TRUE, dry_run=FALSE, datum/export_report/external_report)
if(!GLOB.exports_list.len)
setupExports()
var/profit_ratio = 1 //Percentage that gets sent to the seller, rest goes to cargo.
var/list/contents = AM.GetAllContents()
var/datum/export_report/report = external_report
if(!report) //If we don't have any longer transaction going on
report = new
// We go backwards, so it'll be innermost objects sold first
for(var/i in reverseRange(contents))
var/atom/movable/thing = i
var/sold = FALSE
if(QDELETED(thing))
continue
for(var/datum/export/E in GLOB.exports_list)
if(!E)
continue
if(E.applies_to(thing, allowed_categories, apply_elastic))
sold = E.sell_object(thing, report, dry_run, allowed_categories , apply_elastic, profit_ratio)
report.exported_atoms += " [thing.name]"
if(!QDELETED(thing))
report.exported_atoms_ref += thing
break
if(!dry_run && (sold || delete_unsold))
if(ismob(thing))
thing.investigate_log("deleted through cargo export",INVESTIGATE_CARGO)
qdel(thing)
return report
/datum/export
var/unit_name = "" // Unit name. Only used in "Received [total_amount] [name]s [message]." message
var/message = ""
var/cost = 1 // Cost of item, in cargo credits. Must not alow for infinite price dupes, see above.
var/k_elasticity = 1/30 //coefficient used in marginal price calculation that roughly corresponds to the inverse of price elasticity, or "quantity elasticity"
var/list/export_types = list() // Type of the exported object. If none, the export datum is considered base type.
var/include_subtypes = TRUE // Set to FALSE to make the datum apply only to a strict type.
var/list/exclude_types = list() // Types excluded from export
//cost includes elasticity, this does not.
var/init_cost
//All these need to be present in export call parameter for this to apply.
var/export_category = EXPORT_CARGO
/datum/export/New()
..()
SSprocessing.processing += src
init_cost = cost
export_types = typecacheof(export_types, FALSE, !include_subtypes)
exclude_types = typecacheof(exclude_types)
/datum/export/Destroy()
SSprocessing.processing -= src
return ..()
/datum/export/process()
..()
cost *= NUM_E**(k_elasticity * (1/30))
if(cost > init_cost)
cost = init_cost
// Checks the cost. 0 cost items are skipped in export.
/datum/export/proc/get_cost(obj/O, allowed_categories = NONE, apply_elastic = TRUE)
var/amount = get_amount(O)
if(apply_elastic)
if(k_elasticity!=0)
return round((cost/k_elasticity) * (1 - NUM_E**(-1 * k_elasticity * amount))) //anti-derivative of the marginal cost function
else
return round(cost * amount) //alternative form derived from L'Hopital to avoid division by 0
else
return round(init_cost * amount)
// Checks the amount of exportable in object. Credits in the bill, sheets in the stack, etc.
// Usually acts as a multiplier for a cost, so item that has 0 amount will be skipped in export.
/datum/export/proc/get_amount(obj/O)
return 1
// Checks if the item is fit for export datum.
/datum/export/proc/applies_to(obj/O, allowed_categories = NONE, apply_elastic = TRUE)
if((allowed_categories & export_category) != export_category)
return FALSE
if(!is_type_in_typecache(O, export_types))
return FALSE
if(include_subtypes && is_type_in_typecache(O, exclude_types))
return FALSE
if(!get_cost(O, allowed_categories , apply_elastic))
return FALSE
if(O.flags_1 & HOLOGRAM_1)
return FALSE
return TRUE
/**
* Calculates the exact export value of the object, while factoring in all the relivant variables.
*
* Called only once, when the object is actually sold by the datum.
* Adds item's cost and amount to the current export cycle.
* get_cost, get_amount and applies_to do not neccesary mean a successful sale.
*
*/
/datum/export/proc/sell_object(obj/O, datum/export_report/report, dry_run = TRUE, allowed_categories = EXPORT_CARGO , apply_elastic = TRUE)
///This is the value of the object, as derived from export datums.
var/the_cost = get_cost(O, allowed_categories , apply_elastic)
///Quantity of the object in question.
var/amount = get_amount(O)
///Utilized in the pricetag component. Splits the object's profit when it has a pricetag by the specified amount.
var/profit_ratio = 0
if(amount <=0 || the_cost <=0)
return FALSE
if(dry_run == FALSE)
if(SEND_SIGNAL(O, COMSIG_ITEM_SOLD, item_value = get_cost(O, allowed_categories , apply_elastic)) & COMSIG_ITEM_SPLIT_VALUE)
profit_ratio = SEND_SIGNAL(O, COMSIG_ITEM_SPLIT_PROFIT_DRY)
the_cost = the_cost * ((100 - profit_ratio) * 0.01)
else
profit_ratio = SEND_SIGNAL(O, COMSIG_ITEM_SPLIT_PROFIT)
the_cost = the_cost * ((100 - profit_ratio) * 0.01)
report.total_value[src] += the_cost
if(istype(O, /datum/export/material))
report.total_amount[src] += amount*MINERAL_MATERIAL_AMOUNT
else
report.total_amount[src] += amount
if(!dry_run)
if(apply_elastic)
cost *= NUM_E**(-1*k_elasticity*amount) //marginal cost modifier
SSblackbox.record_feedback("nested tally", "export_sold_cost", 1, list("[O.type]", "[the_cost]"))
return TRUE
// Total printout for the cargo console.
// Called before the end of current export cycle.
// It must always return something if the datum adds or removes any credts.
/datum/export/proc/total_printout(datum/export_report/ex, notes = TRUE)
if(!ex.total_amount[src] || !ex.total_value[src])
return ""
var/total_value = ex.total_value[src]
var/total_amount = ex.total_amount[src]
var/msg = "[total_value] credits: Received [total_amount] "
if(total_value > 0)
msg = "+" + msg
if(unit_name)
msg += unit_name
if(total_amount > 1)
msg += "s"
if(message)
msg += " "
if(message)
msg += message
msg += "."
return msg
GLOBAL_LIST_EMPTY(exports_list)
/proc/setupExports()
for(var/subtype in subtypesof(/datum/export))
var/datum/export/E = new subtype
if(E.export_types && E.export_types.len) // Exports without a type are invalid/base types
GLOB.exports_list += E