Changeset - r20058:431b83660079
[Not reviewed]
master
0 1 0
rubidium - 11 years ago 2013-02-17 20:16:49
rubidium@openttd.org
(svn r25016) -Fix [FS#5476]: integer overflow in UpdateStationRating (fonsinchen)
1 file changed with 3 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/station_cmd.cpp
Show inline comments
 
@@ -3262,97 +3262,99 @@ static void UpdateStationRating(Station 
 
			if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26;
 

	
 
			byte age = ge->last_age;
 
			(age >= 3) ||
 
			(rating += 10, age >= 2) ||
 
			(rating += 10, age >= 1) ||
 
			(rating += 13, true);
 

	
 
			{
 
				int or_ = ge->rating; // old rating
 

	
 
				/* only modify rating in steps of -2, -1, 0, 1 or 2 */
 
				ge->rating = rating = or_ + Clamp(Clamp(rating, 0, 255) - or_, -2, 2);
 

	
 
				/* if rating is <= 64 and more than 200 items waiting,
 
				 * remove some random amount of goods from the station */
 
				if (rating <= 64 && waiting >= 200) {
 
					int dec = Random() & 0x1F;
 
					if (waiting < 400) dec &= 7;
 
					waiting -= dec + 1;
 
					waiting_changed = true;
 
				}
 

	
 
				/* if rating is <= 127 and there are any items waiting, maybe remove some goods. */
 
				if (rating <= 127 && waiting != 0) {
 
					uint32 r = Random();
 
					if (rating <= (int)GB(r, 0, 7)) {
 
						/* Need to have int, otherwise it will just overflow etc. */
 
						waiting = max((int)waiting - (int)GB(r, 8, 2) - 1, 0);
 
						waiting_changed = true;
 
					}
 
				}
 

	
 
				/* At some point we really must cap the cargo. Previously this
 
				 * was a strict 4095, but now we'll have a less strict, but
 
				 * increasingly aggressive truncation of the amount of cargo. */
 
				static const uint WAITING_CARGO_THRESHOLD  = 1 << 12;
 
				static const uint WAITING_CARGO_CUT_FACTOR = 1 <<  6;
 
				static const uint MAX_WAITING_CARGO        = 1 << 15;
 

	
 
				if (waiting > WAITING_CARGO_THRESHOLD) {
 
					uint difference = waiting - WAITING_CARGO_THRESHOLD;
 
					waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
 

	
 
					waiting = min(waiting, MAX_WAITING_CARGO);
 
					waiting_changed = true;
 
				}
 

	
 
				if (waiting_changed) ge->cargo.Truncate(ge->cargo.Count() - waiting);
 
				if (waiting_changed && waiting < ge->cargo.Count()) {
 
					ge->cargo.Truncate(ge->cargo.Count() - waiting);
 
				}
 
			}
 
		}
 
	}
 

	
 
	StationID index = st->index;
 
	if (waiting_changed) {
 
		SetWindowDirty(WC_STATION_VIEW, index); // update whole window
 
	} else {
 
		SetWindowWidgetDirty(WC_STATION_VIEW, index, WID_SV_ACCEPT_RATING_LIST); // update only ratings list
 
	}
 
}
 

	
 
/* called for every station each tick */
 
static void StationHandleSmallTick(BaseStation *st)
 
{
 
	if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
 

	
 
	byte b = st->delete_ctr + 1;
 
	if (b >= STATION_RATING_TICKS) b = 0;
 
	st->delete_ctr = b;
 

	
 
	if (b == 0) UpdateStationRating(Station::From(st));
 
}
 

	
 
void OnTick_Station()
 
{
 
	if (_game_mode == GM_EDITOR) return;
 

	
 
	BaseStation *st;
 
	FOR_ALL_BASE_STATIONS(st) {
 
		StationHandleSmallTick(st);
 

	
 
		/* Run STATION_ACCEPTANCE_TICKS = 250 tick interval trigger for station animation.
 
		 * Station index is included so that triggers are not all done
 
		 * at the same time. */
 
		if ((_tick_counter + st->index) % STATION_ACCEPTANCE_TICKS == 0) {
 
			/* Stop processing this station if it was deleted */
 
			if (!StationHandleBigTick(st)) continue;
 
			TriggerStationAnimation(st, st->xy, SAT_250_TICKS);
 
			if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS);
 
		}
 
	}
 
}
 

	
 
/** Monthly loop for stations. */
 
void StationMonthlyLoop()
 
{
 
	Station *st;
0 comments (0 inline, 0 general)