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

Failed Conditions
Push — main ( 5797ad...3faf69 )
by Dan
29s queued 24s
created

ShopGoodsProcessor::build()   F

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 Globals;
8
use Smr\Page\PlayerPageProcessor;
9
use Smr\Request;
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
		$good_name = Globals::getGoodName($good_id);
36
37
		// do we have enough turns?
38
		if ($player->getTurns() == 0) {
39
			create_error('You don\'t have enough turns to trade.');
40
		}
41
42
		// get rid of those bugs when we die...there is no port at the home sector
43
		if (!$sector->hasPort()) {
44
			create_error('I can\'t see a port in this sector. Can you?');
45
		}
46
		$port = $sector->getPort();
47
48
		// check if the player has the right relations to trade at the current port
49
		if ($player->getRelation($port->getRaceID()) < RELATIONS_WAR) {
50
			create_error('This port refuses to trade with you because you are at <span class="big bold red">WAR!</span>');
51
		}
52
53
		// does the port actually buy or sell this good?
54
		if (!$port->hasGood($good_id)) {
55
			create_error('I don\'t trade in that good.');
56
		}
57
58
		// check if there are enough left at port
59
		if ($port->getGoodAmount($good_id) < $amount) {
60
			create_error('I\'m short of ' . $good_name . '. So I\'m not going to sell you ' . $amount . ' pcs.');
61
		}
62
63
		$transaction = $port->getGoodTransaction($good_id);
64
65
		// does we have what we are going to sell?
66
		if ($transaction === TransactionType::Sell && $amount > $ship->getCargo($good_id)) {
67
			create_error('Scanning your ship indicates you don\'t have ' . $amount . ' pcs. of ' . $good_name . '!');
68
		}
69
70
		// check if we have enough room for the thing we are going to buy
71
		if ($transaction === TransactionType::Buy && $amount > $ship->getEmptyHolds()) {
72
			create_error('Scanning your ship indicates you don\'t have enough free cargo bays!');
73
		}
74
75
		// get relations for us (global + personal)
76
		$relations = $player->getRelation($port->getRaceID());
77
78
		$ideal_price = $this->idealPrice ?? $port->getIdealPrice($good_id, $transaction, $amount, $relations);
79
		$offered_price = $this->offeredPrice ?? $port->getOfferPrice($ideal_price, $relations, $transaction);
80
81
		// nothing should happen here but just to avoid / by 0
82
		if ($ideal_price == 0 || $offered_price == 0) {
83
			create_error('Port calculation error...buy more goods.');
84
		}
85
86
		$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...
87
88
		if (!$stealing && $this->bargainNumber === 0) {
89
			$container = new ShopGoodsNegotiate(
90
				goodID: $this->goodID,
91
				amount: $amount,
92
				bargainNumber: $this->bargainNumber,
93
				bargainPrice: $offered_price,
94
				offeredPrice: $offered_price,
95
				idealPrice: $ideal_price
96
			);
97
			$container->go();
98
		}
99
100
		if ($stealing) {
101
			$bargain_price = 0;
102
		} else {
103
			$bargain_price = $this->bargainPrice ?? Request::getInt('bargain_price');
104
			if ($bargain_price <= 0) {
105
				create_error('You must enter an amount > 0!');
106
			}
107
		}
108
109
		// check if the guy has enough money
110
		if ($transaction === TransactionType::Buy && $player->getCredits() < $bargain_price) {
111
			create_error('You don\'t have enough credits!');
112
		}
113
114
		if ($stealing) {
115
			if (!$ship->isUnderground()) {
116
				throw new Exception('Player tried to steal in a non-underground ship!');
117
			}
118
			if ($transaction !== TransactionType::Buy) {
119
				throw new Exception('Player tried to steal a good the port does not sell!');
120
			}
121
122
			// Small chance to get caught stealing
123
			$catchChancePercent = $port->getMaxLevel() - $port->getLevel() + 1;
124
			if (rand(1, 100) <= $catchChancePercent) {
125
				$fine = $ideal_price * ($port->getLevel() + 1);
126
				// Don't take the trader all the way to 0 credits
127
				$newCredits = max(5000, $player->getCredits() - $fine);
128
				$player->setCredits($newCredits);
129
				$player->decreaseAlignment(5);
130
				$player->decreaseRelationsByTrade($amount, $port->getRaceID());
131
132
				$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>';
133
				$container = new ShopGoods($fineMessage);
134
				$container->go();
135
			}
136
		}
137
138
		// can we accept the current price?
139
		if ($stealing ||
140
			  ($transaction === TransactionType::Buy && $bargain_price >= $ideal_price) ||
141
			  ($transaction === TransactionType::Sell && $bargain_price <= $ideal_price)) {
142
143
			// base xp is the amount you would get for a perfect trade.
144
			// this is the absolut max. the real xp can only be smaller.
145
			$base_xp = SmrPort::getBaseExperience($amount, $port->getGoodDistance($good_id));
146
147
			// if offered equals ideal we get a problem (division by zero)
148
			if ($stealing) {
149
				$expPercent = 1; // stealing gives full exp
150
			} else {
151
				$expPercent = $port->calculateExperiencePercent($ideal_price, $bargain_price, $transaction);
152
			}
153
			$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

153
			$gained_exp = /** @scrutinizer ignore-call */ IRound($expPercent * $base_xp);
Loading history...
154
155
			$portGood = Globals::getGood($good_id);
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
$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
$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
$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