Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

ShopGoodsProcessor::build()   F
last analyzed

Complexity

Conditions 46
Paths > 20000

Size

Total Lines 250
Code Lines 152

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 46
eloc 152
nc 23236608
nop 1
dl 0
loc 250
rs 0
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Smr\Pages\Player;
4
5
use AbstractSmrPlayer;
6
use Exception;
7
use Smr\Page\PlayerPageProcessor;
8
use Smr\Request;
9
use Smr\TradeGood;
10
use Smr\TransactionType;
11
use SmrPort;
12
13
class ShopGoodsProcessor extends PlayerPageProcessor {
14
15
	public function __construct(
16
		private readonly int $goodID,
17
		private readonly ?int $amount = null,
18
		private readonly int $bargainNumber = 0,
19
		private readonly ?int $bargainPrice = null, // only for NPC
20
		private readonly ?int $offeredPrice = null,
21
		private readonly ?int $idealPrice = null
22
	) {}
23
24
	public function build(AbstractSmrPlayer $player): never {
25
		$ship = $player->getShip();
26
		$sector = $player->getSector();
27
28
		$amount = $this->amount ?? Request::getInt('amount');
29
		// no negative amounts are allowed
30
		if ($amount <= 0) {
31
			create_error('You must enter an amount > 0!');
32
		}
33
34
		$good_id = $this->goodID;
35
		$portGood = TradeGood::get($good_id);
36
		$good_name = $portGood->name;
37
38
		// do we have enough turns?
39
		if ($player->getTurns() == 0) {
40
			create_error('You don\'t have enough turns to trade.');
41
		}
42
43
		// get rid of those bugs when we die...there is no port at the home sector
44
		if (!$sector->hasPort()) {
45
			create_error('I can\'t see a port in this sector. Can you?');
46
		}
47
		$port = $sector->getPort();
48
49
		// check if the player has the right relations to trade at the current port
50
		if ($player->getRelation($port->getRaceID()) < RELATIONS_WAR) {
51
			create_error('This port refuses to trade with you because you are at <span class="big bold red">WAR!</span>');
52
		}
53
54
		// does the port actually buy or sell this good?
55
		if (!$port->hasGood($good_id)) {
56
			create_error('I don\'t trade in that good.');
57
		}
58
59
		// check if there are enough left at port
60
		if ($port->getGoodAmount($good_id) < $amount) {
61
			create_error('I\'m short of ' . $good_name . '. So I\'m not going to sell you ' . $amount . ' pcs.');
62
		}
63
64
		$transaction = $port->getGoodTransaction($good_id);
65
66
		// does we have what we are going to sell?
67
		if ($transaction === TransactionType::Sell && $amount > $ship->getCargo($good_id)) {
68
			create_error('Scanning your ship indicates you don\'t have ' . $amount . ' pcs. of ' . $good_name . '!');
69
		}
70
71
		// check if we have enough room for the thing we are going to buy
72
		if ($transaction === TransactionType::Buy && $amount > $ship->getEmptyHolds()) {
73
			create_error('Scanning your ship indicates you don\'t have enough free cargo bays!');
74
		}
75
76
		// get relations for us (global + personal)
77
		$relations = $player->getRelation($port->getRaceID());
78
79
		$ideal_price = $this->idealPrice ?? $port->getIdealPrice($good_id, $transaction, $amount, $relations);
80
		$offered_price = $this->offeredPrice ?? $port->getOfferPrice($ideal_price, $relations, $transaction);
81
82
		// nothing should happen here but just to avoid / by 0
83
		if ($ideal_price == 0 || $offered_price == 0) {
84
			create_error('Port calculation error...buy more goods.');
85
		}
86
87
		$stealing = Request::get('action', '') === TransactionType::STEAL;
0 ignored issues
show
Bug introduced by
The constant Smr\TransactionType::STEAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
88
89
		if (!$stealing && $this->bargainNumber === 0) {
90
			$container = new ShopGoodsNegotiate(
91
				goodID: $this->goodID,
92
				amount: $amount,
93
				bargainNumber: $this->bargainNumber,
94
				bargainPrice: $offered_price,
95
				offeredPrice: $offered_price,
96
				idealPrice: $ideal_price
97
			);
98
			$container->go();
99
		}
100
101
		if ($stealing) {
102
			$bargain_price = 0;
103
		} else {
104
			$bargain_price = $this->bargainPrice ?? Request::getInt('bargain_price');
105
			if ($bargain_price <= 0) {
106
				create_error('You must enter an amount > 0!');
107
			}
108
		}
109
110
		// check if the guy has enough money
111
		if ($transaction === TransactionType::Buy && $player->getCredits() < $bargain_price) {
112
			create_error('You don\'t have enough credits!');
113
		}
114
115
		if ($stealing) {
116
			if (!$ship->isUnderground()) {
117
				throw new Exception('Player tried to steal in a non-underground ship!');
118
			}
119
			if ($transaction !== TransactionType::Buy) {
120
				throw new Exception('Player tried to steal a good the port does not sell!');
121
			}
122
123
			// Small chance to get caught stealing
124
			$catchChancePercent = $port->getMaxLevel() - $port->getLevel() + 1;
125
			if (rand(1, 100) <= $catchChancePercent) {
126
				$fine = $ideal_price * ($port->getLevel() + 1);
127
				// Don't take the trader all the way to 0 credits
128
				$newCredits = max(5000, $player->getCredits() - $fine);
129
				$player->setCredits($newCredits);
130
				$player->decreaseAlignment(5);
131
				$player->decreaseRelationsByTrade($amount, $port->getRaceID());
132
133
				$fineMessage = '<span class="red">A Federation patrol caught you loading stolen goods onto your ship!<br />The stolen goods have been confiscated and you have been fined ' . number_format($fine) . ' credits.</span>';
134
				$container = new ShopGoods($fineMessage);
135
				$container->go();
136
			}
137
		}
138
139
		// can we accept the current price?
140
		if ($stealing ||
141
			  ($transaction === TransactionType::Buy && $bargain_price >= $ideal_price) ||
142
			  ($transaction === TransactionType::Sell && $bargain_price <= $ideal_price)) {
143
144
			// base xp is the amount you would get for a perfect trade.
145
			// this is the absolut max. the real xp can only be smaller.
146
			$base_xp = SmrPort::getBaseExperience($amount, $port->getGoodDistance($good_id));
147
148
			// if offered equals ideal we get a problem (division by zero)
149
			if ($stealing) {
150
				$expPercent = 1; // stealing gives full exp
151
			} else {
152
				$expPercent = $port->calculateExperiencePercent($ideal_price, $bargain_price, $transaction);
153
			}
154
			$gained_exp = IRound($expPercent * $base_xp);
0 ignored issues
show
Bug introduced by
The function IRound was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

154
			$gained_exp = /** @scrutinizer ignore-call */ IRound($expPercent * $base_xp);
Loading history...
155
156
			if ($stealing) {
157
				$msg_transaction = 'stolen';
158
				$ship->increaseCargo($good_id, $amount);
159
				$player->increaseHOF($amount, ['Trade', 'Goods', 'Stolen'], HOF_ALLIANCE);
160
				$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Stealing'], HOF_PUBLIC);
161
				$port->stealGoods($portGood, $amount);
0 ignored issues
show
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $goodsTraded of AbstractSmrPort::stealGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

161
				$port->stealGoods($portGood, /** @scrutinizer ignore-type */ $amount);
Loading history...
162
			} elseif ($transaction === TransactionType::Buy) {
163
				$msg_transaction = 'bought';
164
				$ship->increaseCargo($good_id, $amount);
165
				$player->decreaseCredits($bargain_price);
166
				$player->increaseHOF($amount, ['Trade', 'Goods', 'Bought'], HOF_ALLIANCE);
167
				$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Buying'], HOF_PUBLIC);
168
				$player->decreaseHOF($bargain_price, ['Trade', 'Money', 'Profit'], HOF_PUBLIC);
169
				$player->increaseHOF($bargain_price, ['Trade', 'Money', 'Buying'], HOF_PUBLIC);
170
				$port->buyGoods($portGood, $amount, $ideal_price, $bargain_price, $gained_exp);
0 ignored issues
show
Bug introduced by
$gained_exp of type double is incompatible with the type integer expected by parameter $exp of AbstractSmrPort::buyGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
				$port->buyGoods($portGood, $amount, $ideal_price, $bargain_price, /** @scrutinizer ignore-type */ $gained_exp);
Loading history...
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $goodsTraded of AbstractSmrPort::buyGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
				$port->buyGoods($portGood, /** @scrutinizer ignore-type */ $amount, $ideal_price, $bargain_price, $gained_exp);
Loading history...
Bug introduced by
$bargain_price of type double is incompatible with the type integer expected by parameter $bargainPrice of AbstractSmrPort::buyGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
				$port->buyGoods($portGood, $amount, $ideal_price, /** @scrutinizer ignore-type */ $bargain_price, $gained_exp);
Loading history...
171
				$player->increaseRelationsByTrade($amount, $port->getRaceID());
0 ignored issues
show
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $numGoods of AbstractSmrPlayer::increaseRelationsByTrade(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

171
				$player->increaseRelationsByTrade(/** @scrutinizer ignore-type */ $amount, $port->getRaceID());
Loading history...
172
			} else { // $transaction === TransactionType::Sell
173
				$msg_transaction = 'sold';
174
				$ship->decreaseCargo($good_id, $amount);
175
				$player->increaseCredits($bargain_price);
176
				$player->increaseHOF($amount, ['Trade', 'Goods', 'Sold'], HOF_ALLIANCE);
177
				$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Selling'], HOF_PUBLIC);
178
				$player->increaseHOF($bargain_price, ['Trade', 'Money', 'Profit'], HOF_PUBLIC);
179
				$player->increaseHOF($bargain_price, ['Trade', 'Money', 'Selling'], HOF_PUBLIC);
180
				$port->sellGoods($portGood, $amount, $gained_exp);
0 ignored issues
show
Bug introduced by
$gained_exp of type double is incompatible with the type integer expected by parameter $exp of AbstractSmrPort::sellGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
				$port->sellGoods($portGood, $amount, /** @scrutinizer ignore-type */ $gained_exp);
Loading history...
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $goodsTraded of AbstractSmrPort::sellGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
				$port->sellGoods($portGood, /** @scrutinizer ignore-type */ $amount, $gained_exp);
Loading history...
181
				$player->increaseRelationsByTrade($amount, $port->getRaceID());
182
			}
183
184
			$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Total'], HOF_PUBLIC);
185
			$player->increaseHOF(1, ['Trade', 'Results', 'Success'], HOF_PUBLIC);
186
187
			// log action
188
			$logAction = $stealing ? TransactionType::STEAL : $transaction->value;
189
			$player->log(LOG_TYPE_TRADING, $logAction . 's ' . $amount . ' ' . $good_name . ' for ' . $bargain_price . ' credits and ' . $gained_exp . ' experience');
190
191
			$player->increaseExperience($gained_exp);
0 ignored issues
show
Bug introduced by
$gained_exp of type double is incompatible with the type integer expected by parameter $experience of AbstractSmrPlayer::increaseExperience(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

191
			$player->increaseExperience(/** @scrutinizer ignore-type */ $gained_exp);
Loading history...
192
193
			//will use these variables in current sector and port after successful trade
194
			$tradeMessage = 'You have just ' . $msg_transaction . ' <span class="yellow">' . $amount . '</span> ' . pluralise($amount, 'unit', false) . ' of <span class="yellow">' . $good_name . '</span>';
195
			if ($bargain_price > 0) {
196
				$tradeMessage .= ' for <span class="creds">' . $bargain_price . '</span> ' . pluralise($bargain_price, 'credit', false) . '.';
197
			}
198
199
			if ($gained_exp > 0) {
200
				if ($stealing) {
201
					$qualifier = 'cunning';
202
				} elseif ($gained_exp < $base_xp * 0.25) {
203
					$qualifier = 'novice';
204
				} elseif ($gained_exp < $base_xp * 0.5) {
205
					$qualifier = 'mediocre';
206
				} elseif ($gained_exp < $base_xp * 0.75) {
207
					$qualifier = 'respectable';
208
				} elseif ($gained_exp < IRound($base_xp)) {
209
					$qualifier = 'excellent';
210
				} else {
211
					$qualifier = 'peerless';
212
				}
213
				$skill = $stealing ? 'thievery' : 'trading';
214
				$tradeMessage .= '<br />Your ' . $qualifier . ' ' . $skill . ' skills have earned you <span class="exp">' . $gained_exp . ' </span> ' . pluralise($gained_exp, 'experience point', false) . '!';
215
			}
216
217
			if ($ship->getEmptyHolds() == 0) {
218
				$container = new CurrentSector(tradeMessage: $tradeMessage);
219
			} else {
220
				$container = new ShopGoods($tradeMessage);
221
			}
222
		} else {
223
			// lose relations for bad bargain
224
			$player->decreaseRelationsByTrade($amount, $port->getRaceID());
225
			$player->increaseHOF(1, ['Trade', 'Results', 'Fail'], HOF_PUBLIC);
226
227
			// do we have enough of it?
228
			$maxTries = 5;
229
			if ($this->bargainNumber > 1 && rand($this->bargainNumber, $maxTries) >= $maxTries) {
230
				$player->decreaseRelationsByTrade($amount, $port->getRaceID());
231
				$player->increaseHOF(1, ['Trade', 'Results', 'Epic Fail'], HOF_PUBLIC);
232
				create_error('You don\'t want to accept my offer? I\'m sick of you! Get out of here!');
233
			}
234
235
			$port_off = IRound($offered_price * 100 / $ideal_price);
236
			$trader_off = IRound($bargain_price * 100 / $ideal_price);
237
238
			// get relative numbers!
239
			// be careful! one of this value is negative!
240
			$port_off_rel = 100 - $port_off;
241
			$trader_off_rel = 100 - $trader_off;
242
243
			// Should we change the offer price?
244
			// only do something, if we are more off than the trader
245
			if (abs($port_off_rel) > abs($trader_off_rel)) {
246
				// get a random number between
247
				// (port_off) and (100 +/- $trader_off_rel)
248
				if (100 + $trader_off_rel < $port_off) {
249
					$offer_modifier = rand(100 + $trader_off_rel, $port_off);
250
				} else {
251
					$offer_modifier = rand($port_off, 100 + $trader_off_rel);
252
				}
253
				$offered_price = IRound($ideal_price * $offer_modifier / 100);
254
			}
255
256
			// transfer values to next page
257
			$container = new ShopGoodsNegotiate(
258
				goodID: $this->goodID,
259
				amount: $amount,
260
				bargainNumber: $this->bargainNumber,
261
				bargainPrice: $bargain_price,
262
				offeredPrice: $offered_price,
263
				idealPrice: $ideal_price
264
			);
265
		}
266
267
		// only take turns if they bargained
268
		if (!$stealing) {
269
			$player->takeTurns(TURNS_PER_TRADE, TURNS_PER_TRADE);
270
		}
271
272
		// go to next page
273
		$container->go();
274
	}
275
276
}
277