String StyleResolverStats::report() const
{
    StringBuilder output;

    unsigned sharedStylesRejected = sharedStyleRejectedByAttributeRules;
    unsigned sharedStylesUsed = sharedStyleFound - sharedStylesRejected;

    output.appendLiteral("Style sharing:\n");
    output.append(String::format("  %u elements were added to the sharing candidate list.\n", sharedStyleCandidates));
    output.append(String::format("  %u calls were made to findSharedStyle, %u found a candidate to share with (%.2f%%).\n", sharedStyleLookups, sharedStyleFound, PERCENT(sharedStyleFound, sharedStyleLookups)));
    if (printMissedCandidateCount)
        output.append(String::format("  %u candidates could have matched but were not in the list when searching (%.2f%%).\n", sharedStyleMissed, PERCENT(sharedStyleMissed, sharedStyleLookups)));
    output.append(String::format("  %u of found styles were rejected (%.2f%%), %.2f%% by attribute rules.\n",
        sharedStylesRejected,
        PERCENT(sharedStylesRejected, sharedStyleFound),
        PERCENT(sharedStyleRejectedByAttributeRules, sharedStylesRejected)));
    output.append(String::format("  %u of found styles were used for sharing (%.2f%%).\n", sharedStylesUsed, PERCENT(sharedStylesUsed, sharedStyleFound)));
    output.append(String::format("  %.2f%% of calls to findSharedStyle returned a shared style.\n", PERCENT(sharedStylesUsed, sharedStyleLookups)));

    output.append('\n');

    output.appendLiteral("Matched property cache:\n");
    output.append(String::format("  %u calls to applyMatchedProperties, %u hit the cache (%.2f%%).\n", matchedPropertyApply, matchedPropertyCacheHit, PERCENT(matchedPropertyCacheHit, matchedPropertyApply)));
    output.append(String::format("  %u cache hits also shared the inherited style (%.2f%%).\n", matchedPropertyCacheInheritedHit, PERCENT(matchedPropertyCacheInheritedHit, matchedPropertyCacheHit)));
    output.append(String::format("  %u styles created in applyMatchedProperties were added to the cache (%.2f%%).\n", matchedPropertyCacheAdded, PERCENT(matchedPropertyCacheAdded, matchedPropertyApply)));

    return output.toString();
}
Beispiel #2
0
// ---------------------------------------------------------------------
// Selects all damaged units - on screen toggle.
UDWORD	selSelectAllDamaged( UDWORD player, BOOL bOnScreen)
{
DROID	*psDroid;
UDWORD	damage;
UDWORD	count;

	selDroidDeselect(player);
	for(psDroid = apsDroidLists[player], count = 0;
		psDroid; psDroid = psDroid->psNext)
		{
			/* Get present percent of damage level */
			damage = PERCENT(psDroid->body,psDroid->originalBody);

			/* Less than threshold? */
			if(damage<REPAIRLEV_LOW)
			{
				/* Is on screen relevant? */
				if(bOnScreen ? droidOnScreen(psDroid,0) : true)
				{
                    //we don't want to get the Transporter
	 				if(psDroid->droidType != DROID_TRANSPORTER)
                    {
//    					psDroid->selected = true;
						SelectDroid(psDroid);
	    				count ++;
                    }
				}
			}
		}
	return(count);
}
Beispiel #3
0
bool intDisplayMultiJoiningStatus(UBYTE joinCount)
{
	UDWORD			x,y,w,h;
	char			sTmp[6];

	w = RET_FORMWIDTH;
	h = RET_FORMHEIGHT;
	x = RET_X;
	y = RET_Y;

//	cameraToHome(selectedPlayer);				// home the camera to the player.
	RenderWindowFrame(FRAME_NORMAL, x, y ,w, h);		// draw a wee blu box.

	// display how far done..
	iV_DrawText(_("Players Still Joining"),
					x+(w/2)-(iV_GetTextWidth(_("Players Still Joining"))/2),
					y+(h/2)-8 );
	if (!NetPlay.playercount)
	{
		return true;
	}
	sprintf(sTmp,"%d%%", PERCENT((NetPlay.playercount-joinCount),NetPlay.playercount) );
	iV_DrawText(sTmp ,x + (w / 2) - 10, y + (h / 2) + 10);

	return true;
}
Beispiel #4
0
_export bool module_finit() {
	unregister_packet_handler(D2GS_RECEIVED, 0x9c, d2gs_item_action);
	
	unregister_packet_handler(D2GS_RECEIVED, 0x15, d2gs_char_location_update);
	unregister_packet_handler(D2GS_RECEIVED, 0x95, d2gs_char_location_update);
	unregister_packet_handler(D2GS_SENT, 0x0c, d2gs_char_location_update);

	unregister_packet_handler(D2GS_RECEIVED, 0x19, d2gs_gold_update);
	unregister_packet_handler(D2GS_RECEIVED, 0x1d, d2gs_gold_update);
	unregister_packet_handler(D2GS_RECEIVED, 0x1e, d2gs_gold_update);
	unregister_packet_handler(D2GS_RECEIVED, 0x1f, d2gs_gold_update);
	//unregister_packet_handler(D2GS_RECEIVED, 0x20, d2gs_gold_update);

	//unregister_packet_handler(INTERNAL, 0x9c, internal_trigger_pickit);
	
	list_clear(&items);
	list_clear(&valuable);
	list_clear(&nolog);

	pthread_mutex_destroy(&items_m);

	ui_add_statistics_plugin("pickit", "attempts to pick items: %i\n", n_attempts);
	ui_add_statistics_plugin("pickit", "picked items: %i (%i%%)\n", n_picked, PERCENT(n_attempts, n_picked));

	return TRUE;
}
Beispiel #5
0
bool intDisplayMultiJoiningStatus(UBYTE joinCount)
{
	UDWORD			x,y,w,h;
	char			sTmp[6];

	w = RET_FORMWIDTH;
	h = RET_FORMHEIGHT;
	x = RET_X;
	y = RET_Y;

//	cameraToHome(selectedPlayer);				// home the camera to the player.
	RenderWindowFrame(FRAME_NORMAL, x, y ,w, h);		// draw a wee blu box.

	// display how far done..
	iV_SetFont(font_regular);
	iV_DrawText(_("Players Still Joining"),
					x+(w/2)-(iV_GetTextWidth(_("Players Still Joining"))/2),
					y+(h/2)-8 );
	unsigned playerCount = 0;  // Calculate what NetPlay.playercount should be, which is apparently only non-zero for the host.
	for (unsigned player = 0; player < game.maxPlayers; ++player)
	{
		if (isHumanPlayer(player))
		{
			++playerCount;
		}
	}
	if (!playerCount)
	{
		return true;
	}
	iV_SetFont(font_large);
	sprintf(sTmp, "%d%%", PERCENT(playerCount - joinCount, playerCount));
	iV_DrawText(sTmp ,x + (w / 2) - 10, y + (h / 2) + 10);

	iV_SetFont(font_small);
	int yStep = iV_GetTextLineSize();
	int yPos = RET_Y - yStep*game.maxPlayers;

	static const std::string statusStrings[3] = {"☐ ", "☑ ", "☒ "};

	for (unsigned player = 0; player < game.maxPlayers; ++player)
	{
		int status = -1;
		if (isHumanPlayer(player))
		{
			status = ingame.JoiningInProgress[player]? 0 : 1;  // Human player, still joining or joined.
		}
		else if (NetPlay.players[player].ai >= 0)
		{
			status = 2;  // AI player (automatically joined).
		}
		if (status >= 0)
		{
			iV_DrawText((statusStrings[status] + getPlayerName(player)).c_str(), x + 5, yPos + yStep*NetPlay.players[player].position);
		}
	}

	return true;
}
KeyFileInfo KeyFile::getInfo() {
  KeyFileHeader header;
  readHead(header,false);
  KeyPage page(header.m_keydef.getSize());

  KeyFileInfo result;
  result.m_header          = header;
  result.m_size            = getSize();
  result.m_pageInfo        = m_pageInfo;
  if(header.m_root == DB_NULLADDR) {
    result.m_rootPageAddress   = 0;
    result.m_rootPageItemCount = 0;
    result.m_treeHeight        = 0;
  } else {
    result.m_rootPageAddress = getPageOffset(header.m_root);
    KeyPage page(m_keydef.getSize());
    readPage(header.m_root,page);
    result.m_rootPageItemCount = page.getItemCount();
    result.m_treeHeight  = 1;
    for(KeyPageAddr addr = page.getChild(0); addr; addr = page.getChild(0)) {
      readPage(addr,page);
      result.m_treeHeight++;
    }
  }
  result.m_rootPageIndex = header.m_root;
  result.m_dataPageCount = (UINT)((result.m_size - sizeof(header)) / m_pageInfo.m_pageSize - header.m_freeListSize);

  UINT nonLeafPageCount = 0;
  UINT leafPageCount    = 0;
  CompactIntArray  &pageCountPerLevel = result.m_pageCountPerLevel;

  if(result.m_treeHeight == 0) { // file is empty
    pageCountPerLevel.add(0);
  } else {
    for(UINT l = 0; l < result.m_treeHeight; l++) {
      pageCountPerLevel.add(0);
    }
    pageCountPerLevel.first() = 1;
    KeyPageCounter pageCounter(pageCountPerLevel);
    pageScan(result.m_header.m_root, 0, pageCounter, max(0, result.m_treeHeight-3));
    if(result.m_treeHeight >= 3) {
      for(size_t i = 0; i < pageCountPerLevel.size()-1; i++) {
        nonLeafPageCount += pageCountPerLevel[i];
      }
      leafPageCount = pageCountPerLevel.last() = result.m_dataPageCount - nonLeafPageCount;
    }
  }

  const ULONG totalPageCount = result.m_dataPageCount + header.m_freeListSize;
  if(totalPageCount == 0) {
    result.m_utilizationRate = 100;
  } else {
    const INT64 maxKeys = (INT64)nonLeafPageCount * m_pageInfo.m_maxItemCount + (INT64)leafPageCount * m_pageInfo.m_maxKeyCount;
    result.m_utilizationRate = PERCENT(header.m_keyCount, maxKeys);
  }
  return result;
}
Beispiel #7
0
void	processLight(LIGHT *psLight)
{
SDWORD	tileX,tileY;
SDWORD	startX,endX;
SDWORD	startY,endY;
SDWORD	rangeSkip;
SDWORD	i,j;
SDWORD	distToCorner;
UDWORD	percent;

 	/* Firstly - there's no point processing lights that are off the grid */
	if(clipXY(psLight->position.x,psLight->position.z) == false)
	{
		return;
	}

	tileX = psLight->position.x/TILE_UNITS;
	tileY = psLight->position.z/TILE_UNITS;

	rangeSkip = sqrtf(psLight->range * psLight->range * 2) / TILE_UNITS + 1;

	/* Rough guess? */
	startX = tileX - rangeSkip;
	endX = tileX + rangeSkip;
	startY = tileY - rangeSkip;
	endY = tileY + rangeSkip;

	/* Clip to grid limits */
	startX = MAX(startX, 0);
	endX = MAX(endX, 0);
	endX = MIN(endX, mapWidth - 1);
	startX = MIN(startX, endX);
	startY = MAX(startY, 0);
	endY = MAX(endY, 0);
	endY = MIN(endY, mapHeight - 1);
	startY = MIN(startY, endY);

	for(i=startX;i<=endX; i++)
	{
		for(j=startY; j<=endY; j++)
		{
			distToCorner = calcDistToTile(i,j,&psLight->position);

			/* If we're inside the range of the light */
			if (distToCorner<(SDWORD)psLight->range)
			{
				/* Find how close we are to it */
				percent = 100 - PERCENT(distToCorner,psLight->range);
				colourTile(i, j, psLight->colour, 2 * percent);
			}
		}
	}
}
Beispiel #8
0
_export bool module_finit() {
	unregister_packet_handler(MCP_RECEIVED, 0x07, mcp_charlogon_handler);
	unregister_packet_handler(MCP_RECEIVED, 0x03, mcp_creategame_handler);
	unregister_packet_handler(MCP_RECEIVED, 0x04, mcp_joingame_handler);
	unregister_packet_handler(INTERNAL, D2GS_ENGINE_MESSAGE, on_d2gs_shutdown);

	unregister_packet_handler(INTERNAL, MCP_ENGINE_MESSAGE, on_mcp_cleanup);

	unregister_packet_handler(MCP_RECEIVED, 0x05, mcp_gamelist_handler);

	struct iterator it = list_iterator(&setting_cleaners);
	setting_cleanup_t *sc;
	while ((sc = iterator_next(&it))) {
		sc->cleanup(sc->set);
	}

	list_clear(&setting_cleaners);

	if (keyset) {
		free(keyset);
		keyset = NULL;
		n_keyset = 0;
		i_keyset = 0;
		rotated = FALSE;
	}

	pthread_cond_destroy(&game_created_cond_v);
	pthread_cond_destroy(&game_joined_cond_v);
	pthread_cond_destroy(&mcp_char_logon_cond_v);
	pthread_cond_destroy(&d2gs_engine_shutdown_cond_v);

	pthread_mutex_destroy(&game_created_mutex);
	pthread_mutex_destroy(&game_joined_mutex);
	pthread_mutex_destroy(&mcp_char_logon_mutex);
	pthread_mutex_destroy(&d2gs_engine_shutdown_mutex);

	pthread_mutex_destroy(&mcp_cleanup_m);
	pthread_cond_destroy(&mcp_cleanup_cv);

	pthread_mutex_destroy(&pub_m);
	pthread_cond_destroy(&pub_cv);

	list_clear(&public_games);

	ui_add_statistics_plugin("mcp game", "games created: %i\n", n_created);
	if (module_setting("JoinPublicGames")->b_var) ui_add_statistics_plugin("mcp game", "public games joined: %i\n", n_joined);
	ui_add_statistics_plugin("mcp game", "failed to join: %i (%i%%)\n", ftj, PERCENT(n_created, ftj));

	return TRUE;
}
Beispiel #9
0
// recv lassat info on the receiving end.
bool recvLasSat(NETQUEUE queue)
{
	BASE_OBJECT	*psObj;
	UBYTE		player, targetplayer;
	STRUCTURE	*psStruct;
	uint32_t	id, targetid;

	NETbeginDecode(queue, GAME_LASSAT);
	NETuint8_t(&player);
	NETuint32_t(&id);
	NETuint32_t(&targetid);
	NETuint8_t(&targetplayer);
	NETend();

	psStruct = IdToStruct(id, player);
	psObj	 = IdToPointer(targetid, targetplayer);
	if (psStruct && !canGiveOrdersFor(queue.index, psStruct->player))
	{
		syncDebug("Wrong player.");
		return false;
	}

	if (psStruct && psObj && psStruct->pStructureType->psWeapStat[0]->weaponSubClass == WSC_LAS_SAT)
	{
		// Lassats have just one weapon
		unsigned firePause = weaponFirePause(&asWeaponStats[psStruct->asWeaps[0].nStat], player);
		unsigned damLevel = PERCENT(psStruct->body, structureBody(psStruct));

		if (damLevel < HEAVY_DAMAGE_LEVEL)
		{
			firePause += firePause;
		}

		if (isHumanPlayer(player) && gameTime - psStruct->asWeaps[0].lastFired <= firePause)
		{
			/* Too soon to fire again */
			return true ^ false;  // Return value meaningless and ignored.
		}

		// Give enemy no quarter, unleash the lasat
		proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0);
		psStruct->asWeaps[0].lastFired = gameTime;
		psStruct->asWeaps[0].ammo = 1; // abducting this field for keeping track of triggers

		// Play 5 second countdown message
		audio_QueueTrackPos(ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z);
	}

	return true;
}
Beispiel #10
0
bool PCMAudio_SetStreamVolume( Sfx::sVolume *p_volume, int whichStream )
{
	if( gStreamInfo[whichStream].HasFileStream())
	{
		// Adjust volumes for overall sound volume.
		Spt::SingletonPtr< Sfx::CSfxManager > sfx_manager;

		switch( p_volume->GetVolumeType())
		{
			case Sfx::VOLUME_TYPE_5_CHANNEL_DOLBY5_1:
			{
				float v0	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 0 ));
				float v1	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 1 ));
				float v2	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 2 ));
				float v3	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 3 ));
				float v4	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 4 ));

				gStreamInfo[whichStream].volume = ( v0 + v1 + v2 + v3 + v4 ) * ( 1.0f / 5.0f );
				gStreamInfo[whichStream].SetVolume( v0, v1, v2, v3, v4 );
				break;
			}
			case Sfx::VOLUME_TYPE_2_CHANNEL_DOLBYII:
			{
				float v0	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 0 ));
				float v1	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 1 ));

				gStreamInfo[whichStream].volume = v0;
				gStreamInfo[whichStream].SetVolume( v0, v1 );
				break;
			}
			case Sfx::VOLUME_TYPE_BASIC_2_CHANNEL:
			{
				float v0	= PERCENT( sfx_manager->GetMainVolume(), p_volume->GetChannelVolume( 0 ));

				gStreamInfo[whichStream].volume = v0;
				gStreamInfo[whichStream].SetVolume( v0 );
				break;
			}
			default:
			{
				Dbg_Assert( 0 );
				break;
			}
		}
	}
	return true;
}
Beispiel #11
0
float					CTerrainManager::sGetPitchPercent( STerrainSoundInfo *pInfo, float pitchPercent, bool clipToMaxPitch )
{
	
	Dbg_MsgAssert(pInfo, ("pInfo set to NULL."));

	if ( !( ( pInfo->m_minPitch == 0.0f ) && ( pInfo->m_maxPitch == 100.0f ) ) )
	{
		pitchPercent = ( pInfo->m_minPitch + PERCENT( ( pInfo->m_maxPitch - pInfo->m_minPitch ), pitchPercent ) );
	}
	
	if ( clipToMaxPitch )
	{
		if ( pitchPercent > pInfo->m_maxPitch )
			pitchPercent = pInfo->m_maxPitch;
	}
	return ( pitchPercent );
}
Beispiel #12
0
// set the volume according to the range specified by the designers...
float					CTerrainManager::sGetVolPercent( STerrainSoundInfo *pInfo, float volPercent, bool clipToMaxVol )
{
	
	Dbg_MsgAssert(pInfo, ("pInfo set to NULL."));

	if ( !( ( pInfo->m_minVol == 0.0f ) && ( pInfo->m_maxVol == 100.0f ) ) )
	{
		volPercent = ( pInfo->m_minVol + PERCENT( ( pInfo->m_maxVol - pInfo->m_minVol ), volPercent ) );
	}
	
	if ( clipToMaxVol )
	{
		if ( volPercent > pInfo->m_maxVol )
			volPercent = pInfo->m_maxVol;
	}
	return ( volPercent );
}
Beispiel #13
0
/* test on random values (but relatively small) */
static int
test_2 (void)
{
  guint i;
  guint n_success = 0;
  
  for (i = 0; i < 100000; i++) {
    if (test_float (g_random_int_range (-100000, 100000),
                    g_random_int_range (0, 999999999))) {
      n_success ++;
    }
  }
  g_debug ("%d/%d tests suceeded (%.2f%%)",
           n_success, i, PERCENT (i, n_success));
  
  return n_success == i ? 0 : 1;
}
Beispiel #14
0
static profile_params_set_t COMPANY_PROFILE_PARAMS = {
	.shaper_params = {
		.commit_bps = 50  * MBPS,  .commit_burst      = 1000000,
		.peak_bps   = 0,           .peak_burst        = 0,
		.dual_rate  = FALSE,       .shaper_len_adjust = 20
	},

	.threshold_params = {
		.max_pkts  = 100000,    .enable_max_pkts  = TRUE,
		.max_bytes = 10000000,  .enable_max_bytes = TRUE
	},

	.wred_params = {
		[ODP_PACKET_GREEN ... ODP_PACKET_YELLOW] = {
			.min_threshold     = PERCENT(70),
			.med_threshold     = PERCENT(90),
			.med_drop_prob     = PERCENT(80),
			.max_drop_prob     = PERCENT(100),
			.enable_wred       = TRUE,
			.use_byte_fullness = FALSE,
		},

		[ODP_PACKET_RED] = {
			.min_threshold     = PERCENT(40),
			.med_threshold     = PERCENT(70),
			.med_drop_prob     = PERCENT(70),
			.max_drop_prob     = PERCENT(100),
			.enable_wred       = TRUE,
			.use_byte_fullness = FALSE,
		},
Beispiel #15
0
static Word*
subsub(Word *v, char *s, char *end)
{
	int nmid;
	Word *head, *tail, *w, *h;
	Word *a, *b, *c, *d;
	Bufblock *buf;
	char *cp, *enda;

	a = extractpat(s, &cp, "=%&", end);
	b = c = d = 0;
	if(PERCENT(*cp))
		b = extractpat(cp+1, &cp, "=", end);
	if(*cp == '=')
		c = extractpat(cp+1, &cp, "&%", end);
	if(PERCENT(*cp))
		d = stow(cp+1);
	else if(*cp)
		d = stow(cp);

	head = tail = 0;
	buf = newbuf();
	for(; v; v = v->next){
		h = w = 0;
		if(submatch(v->s, a, b, &nmid, &enda)){
			/* enda points to end of A match in source;
			 * nmid = number of chars between end of A and start of B
			 */
			if(c){
				h = w = wdup(c);
				while(w->next)
					w = w->next;
			}
			if(PERCENT(*cp) && nmid > 0){	
				if(w){
					bufcpy(buf, w->s, strlen(w->s));
					bufcpy(buf, enda, nmid);
					insert(buf, 0);
					free(w->s);
					w->s = strdup(buf->start);
				} else {
					bufcpy(buf, enda, nmid);
					insert(buf, 0);
					h = w = newword(buf->start);
				}
				buf->current = buf->start;
			}
			if(d && *d->s){
				if(w){

					bufcpy(buf, w->s, strlen(w->s));
					bufcpy(buf, d->s, strlen(d->s));
					insert(buf, 0);
					free(w->s);
					w->s = strdup(buf->start);
					w->next = wdup(d->next);
					while(w->next)
						w = w->next;
					buf->current = buf->start;
				} else
					h = w = wdup(d);
			}
		}
		if(w == 0)
			h = w = newword(v->s);
	
		if(head == 0)
			head = h;
		else
			tail->next = h;
		tail = w;
	}
	freebuf(buf);
	delword(a);
	delword(b);
	delword(c);
	delword(d);
	return head;
}
Beispiel #16
0
void
DumpArenaStats(JSGCArenaStats *stp, FILE *fp)
{
    size_t sumArenas = 0, sumTotalArenas = 0, sumThings =0,  sumMaxThings = 0;
    size_t sumThingSize = 0, sumTotalThingSize = 0, sumArenaCapacity = 0;
    size_t sumTotalArenaCapacity = 0, sumAlloc = 0, sumLocalAlloc = 0;

    for (int i = 0; i < (int) FINALIZE_LIMIT; i++) {
        JSGCArenaStats *st = &stp[i];
        if (st->maxarenas == 0)
            continue;
        size_t thingSize = 0, thingsPerArena = 0;
        GetSizeAndThingsPerArena(i, thingSize, thingsPerArena);

        fprintf(fp, "%s arenas (thing size %lu, %lu things per arena):\n",
                GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena));
        fprintf(fp, "           arenas before GC: %lu\n", UL(st->narenas));
        fprintf(fp, "            arenas after GC: %lu (%.1f%%)\n",
                UL(st->livearenas), PERCENT(st->livearenas, st->narenas));
        fprintf(fp, "                 max arenas: %lu\n", UL(st->maxarenas));
        fprintf(fp, "                     things: %lu\n", UL(st->nthings));
        fprintf(fp, "        GC cell utilization: %.1f%%\n",
                PERCENT(st->nthings, thingsPerArena * st->narenas));
        fprintf(fp, "   average cell utilization: %.1f%%\n",
                PERCENT(st->totalthings, thingsPerArena * st->totalarenas));
        fprintf(fp, "                 max things: %lu\n", UL(st->maxthings));
        fprintf(fp, "             alloc attempts: %lu\n", UL(st->alloc));
        fprintf(fp, "        alloc without locks: %lu  (%.1f%%)\n",
                UL(st->localalloc), PERCENT(st->localalloc, st->alloc));
        sumArenas += st->narenas;
        sumTotalArenas += st->totalarenas;
        sumThings += st->nthings;
        sumMaxThings += st->maxthings;
        sumThingSize += thingSize * st->nthings;
        sumTotalThingSize += size_t(thingSize * st->totalthings);
        sumArenaCapacity += thingSize * thingsPerArena * st->narenas;
        sumTotalArenaCapacity += thingSize * thingsPerArena * st->totalarenas;
        sumAlloc += st->alloc;
        sumLocalAlloc += st->localalloc;
        putc('\n', fp);
    }

    fputs("Never used arenas:\n", fp);
    for (int i = 0; i < (int) FINALIZE_LIMIT; i++) {
        JSGCArenaStats *st = &stp[i];
        if (st->maxarenas != 0)
            continue;
        fprintf(fp, "%s\n", GC_ARENA_NAMES[i]);
    }
    fprintf(fp, "\nTOTAL STATS:\n");
    fprintf(fp, "            total GC arenas: %lu\n", UL(sumArenas));
    fprintf(fp, "            total GC things: %lu\n", UL(sumThings));
    fprintf(fp, "        max total GC things: %lu\n", UL(sumMaxThings));
    fprintf(fp, "        GC cell utilization: %.1f%%\n",
            PERCENT(sumThingSize, sumArenaCapacity));
    fprintf(fp, "   average cell utilization: %.1f%%\n",
            PERCENT(sumTotalThingSize, sumTotalArenaCapacity));
    fprintf(fp, "             alloc attempts: %lu\n", UL(sumAlloc));
    fprintf(fp, "        alloc without locks: %lu  (%.1f%%)\n",
            UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc));
}
Beispiel #17
0
/* Add the Droids back at home form */
bool intAddDroidsAvailForm(void)
{
	UDWORD			numButtons, i, butPerForm;
	SDWORD			BufferID;
	DROID			*psDroid;
	bool			Animate = true;

	// Is the form already up?
	if (widgGetFromID(psWScreen, IDTRANS_DROIDS) != NULL)
	{
		intRemoveTransDroidsAvailNoAnim();
		Animate = false;
	}

	if (intIsRefreshing())
	{
		Animate = false;
	}

	/* Add the droids available form */
	W_FORMINIT sFormInit;
	sFormInit.formID = 0;
	sFormInit.id = IDTRANS_DROIDS;
	sFormInit.style = WFORM_PLAIN;
	sFormInit.width = TRANSDROID_WIDTH;
	sFormInit.height = TRANSDROID_HEIGHT;
	sFormInit.x = (SWORD)TRANSDROID_X;
	sFormInit.y = (SWORD)TRANSDROID_Y;

	// If the window was closed then do open animation.
	if (Animate)
	{
		sFormInit.pDisplay = intOpenPlainForm;
		sFormInit.disableChildren = true;
	}
	else
	{
		// otherwise just recreate it.
		sFormInit.pDisplay = intDisplayPlainForm;
	}

	if (!widgAddForm(psWScreen, &sFormInit))
	{
		return false;
	}

	/* Add the close button */
	W_BUTINIT sButInit;
	sButInit.formID = IDTRANS_DROIDS;
	sButInit.id = IDTRANS_DROIDCLOSE;
	sButInit.x = TRANSDROID_WIDTH - CLOSE_WIDTH;
	sButInit.y = 0;
	sButInit.width = CLOSE_WIDTH;
	sButInit.height = CLOSE_HEIGHT;
	sButInit.pTip = _("Close");
	sButInit.pDisplay = intDisplayImageHilight;
	sButInit.UserData = PACKDWORD_TRI(0, IMAGE_CLOSEHILIGHT , IMAGE_CLOSE);
	if (!widgAddButton(psWScreen, &sButInit))
	{
		return false;
	}

	//now add the tabbed droids available form
	sFormInit = W_FORMINIT();
	sFormInit.formID = IDTRANS_DROIDS;
	sFormInit.id = IDTRANS_DROIDTAB;
	sFormInit.style = WFORM_TABBED;
	sFormInit.width = TRANSDROID_TABWIDTH;
	sFormInit.height = TRANSDROID_TABHEIGHT;
	sFormInit.x = TRANSDROID_TABX;
	sFormInit.y = TRANSDROID_TABY;

	sFormInit.majorPos = WFORM_TABTOP;
	sFormInit.minorPos = WFORM_TABNONE;

	sFormInit.majorSize = (OBJ_TABWIDTH / 2);

	sFormInit.majorOffset = OBJ_TABOFFSET;
	sFormInit.tabVertOffset = (OBJ_TABHEIGHT / 2);
	sFormInit.tabMajorThickness = OBJ_TABHEIGHT;
	sFormInit.tabMajorGap = OBJ_TABOFFSET;

	//calc num buttons
	numButtons = 0;
	//look through the list of droids that were built before the mission
	for (psDroid = mission.apsDroidLists[selectedPlayer]; psDroid; psDroid = psDroid->psNext)
	{
		//ignore any Transporters!
		if (psDroid->droidType != DROID_TRANSPORTER && psDroid->droidType != DROID_SUPERTRANSPORTER)
		{
			numButtons++;
		}
		//quit when reached max can cope with
		if (numButtons == MAX_DROIDS)
		{
			break;
		}
	}

	butPerForm = ((TRANSDROID_TABWIDTH - OBJ_GAP) /
	        (OBJ_BUTWIDTH + OBJ_GAP)) *
	        ((TRANSDROID_TABHEIGHT - OBJ_GAP) /
	                (OBJ_BUTHEIGHT + OBJ_GAP));

	sFormInit.numMajor = numForms(numButtons, butPerForm);
	if (sFormInit.numMajor > MAX_TAB_SMALL_SHOWN)
	{
		// we DO use smallTab icons here, so be safe and only display max # of
		// small sized tab icons. No scrolltabs here.
		sFormInit.numMajor = MAX_TAB_SMALL_SHOWN;
	}
	//set minor tabs to 1
	for (i = 0; i < sFormInit.numMajor; i++)
	{
		sFormInit.aNumMinors[i] = 1;
	}

	sFormInit.pUserData = &SmallTab;

	sFormInit.pTabDisplay = intDisplayTab;

	if (!widgAddForm(psWScreen, &sFormInit))
	{
		return false;
	}

	/* Add the droids available buttons */
	W_FORMINIT sBFormInit;
	sBFormInit.formID = IDTRANS_DROIDTAB;
	sBFormInit.id = IDTRANS_DROIDSTART;
	sBFormInit.majorID = 0;
	sBFormInit.minorID = 0;
	sBFormInit.style = WFORM_CLICKABLE;
	sBFormInit.x = OBJ_STARTX;
	sBFormInit.y = AVAIL_STARTY;
	sBFormInit.width = OBJ_BUTWIDTH;
	sBFormInit.height = OBJ_BUTHEIGHT;

	ClearSystem0Buffers();

	/* Add the state of repair bar for each droid*/
	W_BARINIT sBarInit;
	sBarInit.id = IDTRANS_REPAIRBARSTART;
	sBarInit.x = STAT_TIMEBARX;
	sBarInit.y = STAT_TIMEBARY;
	sBarInit.width = STAT_PROGBARWIDTH;
	sBarInit.height = STAT_PROGBARHEIGHT;
	sBarInit.size = 50;
	sBarInit.sCol = WZCOL_ACTION_PROGRESS_BAR_MAJOR;
	sBarInit.sMinorCol = WZCOL_ACTION_PROGRESS_BAR_MINOR;

	//add droids built before the mission
	for (psDroid = mission.apsDroidLists[selectedPlayer]; psDroid != NULL; psDroid = psDroid->psNext)
	{
		//stop adding the buttons once MAX_DROIDS has been reached
		if (sBFormInit.id == (IDTRANS_DROIDSTART + MAX_DROIDS))
		{
			break;
		}
		//don't add Transporter Droids!
		if ((psDroid->droidType != DROID_TRANSPORTER && psDroid->droidType != DROID_SUPERTRANSPORTER))
		{
			/* Set the tip and add the button */
			sBFormInit.pTip = droidGetName(psDroid);
			BufferID = GetSystem0Buffer();
			ASSERT(BufferID >= 0, "Unable to acquire stat buffer.");
			RENDERBUTTON_INUSE(&System0Buffers[BufferID]);
			System0Buffers[BufferID].Data = (void *)psDroid;
			sBFormInit.pUserData = &System0Buffers[BufferID];
			sBFormInit.pDisplay = intDisplayTransportButton;

			if (!widgAddForm(psWScreen, &sBFormInit))
			{
				return false;
			}

			//add bar to indicate stare of repair
			sBarInit.size = (UWORD) PERCENT(psDroid->body, psDroid->originalBody);
			if (sBarInit.size > 100)
			{
				sBarInit.size = 100;
			}

			sBarInit.formID = sBFormInit.id;
			//sBarInit.iRange = TBAR_MAX_REPAIR;
			if (!widgAddBarGraph(psWScreen, &sBarInit))
			{
				return false;
			}

			/* Update the init struct for the next button */
			sBFormInit.id += 1;
			ASSERT(sBFormInit.id < IDTRANS_DROIDEND, "Too many Droids Built buttons");

			sBFormInit.x += OBJ_BUTWIDTH + OBJ_GAP;
			if (sBFormInit.x + OBJ_BUTWIDTH + OBJ_GAP > TRANSDROID_TABWIDTH)
			{
				sBFormInit.x = OBJ_STARTX;
				sBFormInit.y += OBJ_BUTHEIGHT + OBJ_GAP;
			}

			if (sBFormInit.y + OBJ_BUTHEIGHT + OBJ_GAP > TRANSDROID_TABHEIGHT)
			{
				sBFormInit.y = AVAIL_STARTY;
				sBFormInit.majorID += 1;
			}
			//and bar
			sBarInit.id += 1;
		}
	}

	//reset which tab we were on
	if (objMajor > (UWORD)(sFormInit.numMajor - 1))
	{
		//set to last if have lost a tab
		widgSetTabs(psWScreen, IDTRANS_DROIDTAB, (UWORD)(sFormInit.numMajor - 1), objMinor);
	}
	else
	{
		//set to same tab we were on previously
		widgSetTabs(psWScreen, IDTRANS_DROIDTAB, objMajor, objMinor);
	}

	return true;
}
Beispiel #18
0
// -----------------------------------------------------------------------------------
void	fillUpStats( void )
{
	UDWORD	i;
	UDWORD	maxi,num;
	float	scaleFactor;
	UDWORD	length;
	UDWORD	numUnits;
	DROID	*psDroid;

	/* Do rankings first cos they're easier */
	for(i=0,maxi=0; i<DROID_LEVELS; i++)
	{
		num = getNumDroidsForLevel(i);
		if(num>maxi)
		{
			maxi = num;
		}
	}

	/* Make sure we got something */
	if(maxi == 0)
	{
		scaleFactor = 0.f;
	}
	else
	{
		scaleFactor = (float)RANK_BAR_WIDTH / maxi;
	}

	/* Scale for percent */
	for(i=0; i<DROID_LEVELS; i++)
	{
		length = scaleFactor * getNumDroidsForLevel(i);
		infoBars[STAT_ROOKIE+i].percent = PERCENT(length,RANK_BAR_WIDTH);
		infoBars[STAT_ROOKIE+i].number = getNumDroidsForLevel(i);
	}

	/* Now do the other stuff... */
	/* Units killed and lost... */
	maxi = MAX(missionData.unitsLost, missionData.unitsKilled);
	if (maxi == 0)
	{
		scaleFactor = 0.f;
	}
	else
	{
		scaleFactor = (float)STAT_BAR_WIDTH / maxi;
	}

	length = scaleFactor * missionData.unitsLost;
	infoBars[STAT_UNIT_LOST].percent = PERCENT(length,STAT_BAR_WIDTH);
	length = scaleFactor * missionData.unitsKilled;
	infoBars[STAT_UNIT_KILLED].percent = PERCENT(length,STAT_BAR_WIDTH);

	/* Now do the structure losses */
	maxi = MAX(missionData.strLost, missionData.strKilled);
	if (maxi == 0)
	{
		scaleFactor = 0.f;
	}
	else
	{
		scaleFactor = (float)STAT_BAR_WIDTH / maxi;
	}

	length = scaleFactor * missionData.strLost;
	infoBars[STAT_STR_LOST].percent = PERCENT(length,STAT_BAR_WIDTH);
	length = scaleFactor * missionData.strKilled;
	infoBars[STAT_STR_BLOWN_UP].percent = PERCENT(length,STAT_BAR_WIDTH);

	/* Finally the force information - need amount of droids as well*/
	for(psDroid = apsDroidLists[selectedPlayer], numUnits = 0; psDroid; psDroid = psDroid->psNext, numUnits++) {}

	for(psDroid = mission.apsDroidLists[selectedPlayer]; psDroid; psDroid = psDroid->psNext, numUnits++) {}

	maxi = MAX(missionData.unitsBuilt, missionData.strBuilt);
	maxi = MAX(maxi, numUnits);

	if (maxi == 0)
	{
		scaleFactor = 0.f;
	}
	else
	{
		scaleFactor = (float)STAT_BAR_WIDTH / maxi;
	}

	length = scaleFactor * missionData.unitsBuilt;
	infoBars[STAT_UNITS_BUILT].percent = PERCENT(length,STAT_BAR_WIDTH);
	length = scaleFactor * numUnits;
	infoBars[STAT_UNITS_NOW].percent = PERCENT(length,STAT_BAR_WIDTH);
	length = scaleFactor * missionData.strBuilt;
	infoBars[STAT_STR_BUILT].percent = PERCENT(length,STAT_BAR_WIDTH);

	/* Finally the numbers themselves */
	infoBars[STAT_UNIT_LOST].number = missionData.unitsLost;
	infoBars[STAT_UNIT_KILLED].number = missionData.unitsKilled;
	infoBars[STAT_STR_LOST].number = missionData.strLost;
	infoBars[STAT_STR_BLOWN_UP].number = missionData.strKilled;
	infoBars[STAT_UNITS_BUILT].number =	missionData.unitsBuilt;
	infoBars[STAT_UNITS_NOW].number = numUnits;
	infoBars[STAT_STR_BUILT].number = missionData.strBuilt;
}
Beispiel #19
0
/* Add the Droids back at home form */
bool intAddDroidsAvailForm(void)
{
	// Is the form already up?
	bool Animate = true;
	if (widgGetFromID(psWScreen, IDTRANS_DROIDS) != NULL)
	{
		intRemoveTransDroidsAvailNoAnim();
		Animate = false;
	}

	if (intIsRefreshing())
	{
		Animate = false;
	}

	WIDGET *parent = psWScreen->psForm;

	/* Add the droids available form */
	IntFormAnimated *transDroids = new IntFormAnimated(parent, Animate);  // Do not animate the opening, if the window was already open.
	transDroids->id = IDTRANS_DROIDS;
	transDroids->setGeometry(TRANSDROID_X, TRANSDROID_Y, TRANSDROID_WIDTH, TRANSDROID_HEIGHT);

	/* Add the close button */
	W_BUTINIT sButInit;
	sButInit.formID = IDTRANS_DROIDS;
	sButInit.id = IDTRANS_DROIDCLOSE;
	sButInit.x = TRANSDROID_WIDTH - CLOSE_WIDTH;
	sButInit.y = 0;
	sButInit.width = CLOSE_WIDTH;
	sButInit.height = CLOSE_HEIGHT;
	sButInit.pTip = _("Close");
	sButInit.pDisplay = intDisplayImageHilight;
	sButInit.UserData = PACKDWORD_TRI(0, IMAGE_CLOSEHILIGHT , IMAGE_CLOSE);
	if (!widgAddButton(psWScreen, &sButInit))
	{
		return false;
	}

	//now add the tabbed droids available form
	IntListTabWidget *droidList = new IntListTabWidget(transDroids);
	droidList->id = IDTRANS_DROIDTAB;
	droidList->setChildSize(OBJ_BUTWIDTH, OBJ_BUTHEIGHT);
	droidList->setChildSpacing(OBJ_GAP, OBJ_GAP);
	int droidListWidth = OBJ_BUTWIDTH*2 + OBJ_GAP;
	droidList->setGeometry((TRANSDROID_WIDTH - droidListWidth)/2, AVAIL_STARTY + 15, droidListWidth, TRANSDROID_HEIGHT - (AVAIL_STARTY + 15));

	/* Add the droids available buttons */
	int nextButtonId = IDTRANS_DROIDSTART;

	/* Add the state of repair bar for each droid*/
	W_BARINIT sBarInit;
	sBarInit.id = IDTRANS_REPAIRBARSTART;
	sBarInit.x = STAT_TIMEBARX;
	sBarInit.y = STAT_TIMEBARY;
	sBarInit.width = STAT_PROGBARWIDTH;
	sBarInit.height = STAT_PROGBARHEIGHT;
	sBarInit.size = 50;
	sBarInit.sCol = WZCOL_ACTION_PROGRESS_BAR_MAJOR;
	sBarInit.sMinorCol = WZCOL_ACTION_PROGRESS_BAR_MINOR;

	//add droids built before the mission
	for (DROID *psDroid = mission.apsDroidLists[selectedPlayer]; psDroid != nullptr; psDroid = psDroid->psNext)
	{
		//stop adding the buttons once IDTRANS_DROIDEND has been reached
		if (nextButtonId == IDTRANS_DROIDEND)
		{
			break;
		}
		//don't add Transporter Droids!
		if ((psDroid->droidType != DROID_TRANSPORTER && psDroid->droidType != DROID_SUPERTRANSPORTER))
		{
			/* Set the tip and add the button */
			IntTransportButton *button = new IntTransportButton(droidList);
			button->id = nextButtonId;
			button->setTip(droidGetName(psDroid));
			button->setObject(psDroid);
			droidList->addWidgetToLayout(button);

			//add bar to indicate stare of repair
			sBarInit.size = (UWORD) PERCENT(psDroid->body, psDroid->originalBody);
			if (sBarInit.size > 100)
			{
				sBarInit.size = 100;
			}

			sBarInit.formID = nextButtonId;
			//sBarInit.iRange = TBAR_MAX_REPAIR;
			if (!widgAddBarGraph(psWScreen, &sBarInit))
			{
				return false;
			}

			/* Update the init struct for the next button */
			++nextButtonId;
			ASSERT(nextButtonId < IDTRANS_DROIDEND, "Too many Droids Built buttons");

			//and bar
			sBarInit.id += 1;
		}
	}

	//reset which tab we were on
	droidList->setCurrentPage(objMajor);

	return true;
}
/**
 * Calculate and obtain the core variables. Each raw ADC value is converted to a
 * usable measurement via a variety of methods. They are then stored in a struct
 * and used as input to the next phase.
 */
void generateCoreVars(){
	// Battery Reference Voltage
	unsigned short localBRV;
	if(!(fixedConfigs2.sensorSources.BRV)){
		localBRV = (((unsigned long)ADCBuffers->BRV * fixedConfigs2.sensorRanges.BRVRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.BRVMinimum;
	}else if(fixedConfigs2.sensorSources.BRV == SOURCE_PRESET){
		localBRV = fixedConfigs2.sensorPresets.presetBRV;
	}else if(fixedConfigs2.sensorSources.BRV == SOURCE_LINEAR){
		localBRV = (ADCBuffers->BRV * 14) + VOLTS(7.2); // 0 ADC = 7.2V, 1023 ADC = 21.522C
	}else{ // Default to normal alternator charging voltage 14.4V
		localBRV = VOLTS(14.4);
	}

	// Coolant/Head Temperature
	unsigned short localCHT;
	if(!(fixedConfigs2.sensorSources.CHT)){
		localCHT = CHTTransferTable[ADCBuffers->CHT];
	}else if(fixedConfigs2.sensorSources.CHT == SOURCE_PRESET){
		localCHT = fixedConfigs2.sensorPresets.presetCHT;
	}else if(fixedConfigs2.sensorSources.CHT == SOURCE_LINEAR){
		localCHT = (ADCBuffers->CHT * 10) + DEGREES_C(0); // 0 ADC = 0C, 1023 ADC = 102.3C
	}else{ // Default to slightly cold and therefore rich: 65C
		localCHT = DEGREES_C(65);
	}

	// Inlet Air Temperature
	unsigned short localIAT;
	if(!(fixedConfigs2.sensorSources.IAT)){
		localIAT = IATTransferTable[ADCBuffers->IAT];
	}else if(fixedConfigs2.sensorSources.IAT == SOURCE_PRESET){
		localIAT = fixedConfigs2.sensorPresets.presetIAT;
	}else if(fixedConfigs2.sensorSources.IAT == SOURCE_LINEAR){
		localIAT = (ADCBuffers->IAT * 10) + DEGREES_C(0); // 0 ADC = 0C, 1023 ADC = 102.3C
	}else{ // Default to room temperature
		localIAT = DEGREES_C(20);
	}

	// Throttle Position Sensor
	/* Bound the TPS ADC reading and shift it to start at zero */
	unsigned short unboundedTPSADC = ADCBuffers->TPS;
	unsigned short boundedTPSADC;
	if(fixedConfigs2.sensorRanges.TPSMaximumADC > fixedConfigs2.sensorRanges.TPSMinimumADC){
		if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMaximumADC){
			boundedTPSADC = TPSADCRange;
		}else if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMinimumADC){
			boundedTPSADC = unboundedTPSADC - fixedConfigs2.sensorRanges.TPSMinimumADC;
		} else{
			boundedTPSADC = 0;
		}
	}else{ // Reverse slope!
		if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMinimumADC){
			boundedTPSADC = 0;
		}else if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMaximumADC){
			boundedTPSADC = fixedConfigs2.sensorRanges.TPSMinimumADC - unboundedTPSADC;
		}else{
			boundedTPSADC = TPSADCRange;
		}
	}

	/* Get TPS from ADC no need to add TPS min as we know it is zero by definition */
	unsigned short localTPS = ((unsigned long)boundedTPSADC * PERCENT(100)) / TPSADCRange;
	// TODO fail safe mode, only if on the ADC rails AND configured to do so
	// Default to a low value that will get you home if you are in Alpha-N mode

	/* Get RPM by locking out ISRs for a second and grabbing the Tooth logging data */
	//atomic start
	// copy rpm data
	//atomic end

	// Calculate RPM and delta RPM and delta delta RPM from data recorded
	if(*ticksPerDegree != 0){
		CoreVars->RPM = (unsigned short)(degreeTicksPerMinute / *ticksPerDegree);
	}else{
		CoreVars->RPM = 0;
	}

	CoreVars->DRPM = *ticksPerDegree;
//	unsigned short localDRPM = 0;
//	unsigned short localDDRPM = 0;


	// TODO This might get done somewhere else, separation of concerns, etc
	/*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Average the variables as per the configuration &&&&&&&&&&&&&&&&&&&&&&&&&&*/
	/* Strictly speaking only the primary variables need to be averaged. After that, the derived ones are   */
	/* already averaged in a way. However, there may be some advantage to some short term averaging on the  */
	/* derived ones also, so it is something to look into later.                                            */

	/// @todo TODO average the generated values here

//			newVal var word        ' the value from the ADC
//			smoothed var word    ' a nicely smoothed result
//
//			if newval > smoothed then
//			        smoothed = smoothed + (newval - smoothed)/alpha
//			else
//			        smoothed = smoothed - (smoothed - newval)/alpha
//			endif

	// from : http://www.tigoe.net/pcomp/code/category/code/arduinowiring/41

	// for now just copy them in.
	CoreVars->BRV = localBRV;
	CoreVars->CHT = localCHT;
	CoreVars->IAT = localIAT;
	CoreVars->TPS = localTPS;
	CoreVars->EGO = (((unsigned long)ADCBuffers->EGO * fixedConfigs2.sensorRanges.EGORange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.EGOMinimum;
	CoreVars->MAP = (((unsigned long)ADCBuffers->MAP * fixedConfigs2.sensorRanges.MAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.MAPMinimum;
	CoreVars->AAP = (((unsigned long)ADCBuffers->AAP * fixedConfigs2.sensorRanges.AAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.AAPMinimum;
	CoreVars->MAT = IATTransferTable[ADCBuffers->MAT];


	// Not actually used, feed raw values for now TODO migrate these to a SpecialVars struct or similar not included in default datalog
	CoreVars->EGO2 = ADCBuffers->EGO2;
	CoreVars->IAP = ADCBuffers->IAP;
	CoreVars->MAF = MAFTransferTable[ADCBuffers->MAF];

//	CoreVars->DRPM = localDRPM;
//	CoreVars->DDRPM = localDDRPM;
//	CoreVars->DTPS = localDTPS;
}
Beispiel #21
0
static bool selDamaged(DROID *droid)
{
	return PERCENT(droid->body, droid->originalBody) < REPAIRLEV_LOW && !selTransporter(droid);
}
Beispiel #22
0
	ECCPowerDownInProgress = 0x10000000u,
	ECCRebalanceRequired = 0x08000000u,
	ECCRebalanceTimerQueued = 0x04000000u,
	ECCPeriodicBalancingActive = 0x02000000u,
	};

const TUint K_CpuMask	= 0x1fu;
const TUint K_Keep		= 0x20u;
const TUint K_SameCpu	= 0x40u;
const TUint K_NewCpu	= 0x80u;
const TUint K_CpuSticky	= 0x40u;
const TUint K_CheckCpu	= 0x100u;

#define	PERCENT(fsd, percent)					(((fsd)*(percent)+50)/100)

const TUint K_LB_HeavyThreshold					= PERCENT(4095, 90);
const TUint K_LB_GravelThreshold_RunAvg			= PERCENT(4095, 1);
const TUint K_LB_GravelThreshold_RunActAvg		= PERCENT(4095, 50);
const TInt	K_LB_HeavyCapacityThreshold			= PERCENT(4095, 1);
const TInt	K_LB_BalanceInterval				= 107;
const TInt	K_LB_CpuLoadDiffThreshold			= 128;

//const TUint K_LB_HeavyStateThreshold			= 128;
const TUint K_LB_HeavyPriorityThreshold			= 25;

inline TBool IsHeavy(NSchedulable* a)
	{
	TUint x = 0xffu ^ a->iLbInfo.iLbHeavy;
	return (x&(x-1))==0;
	}
/** @brief Generate the core variables and average them.
 *
 * Each raw ADC value is converted to a usable measurement via a variety of
 * methods chosen at runtime by configured settings. Once in their native units
 * and therefore closer to maximal use of the available data range they are
 * all averaged.
 *
 * @todo TODO incorporate averaging code, right now its a straight copy.
 * @todo TODO change the way configuration is done and make sure the most common options are after the first if().
 * @todo TODO add actual configuration options to the fixed config blocks for these items.
 *
 * @author Fred Cooke
 */
void generateCoreVars(){
	/*&&&&&&&& Calculate and obtain the basic variables with which we will perform the calculations &&&&&&&&*/


	/* Pre calculate things used in multiple places */

	/* Bound the TPS ADC reading and shift it to start at zero */
	unsigned short unboundedTPSADC = ADCBuffers->TPS;
	if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMaximumADC){
		boundedTPSADC = TPSADCRange;
	}else if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMinimumADC){ // force secondary config to be used... TODO remove this
		boundedTPSADC = unboundedTPSADC - fixedConfigs2.sensorRanges.TPSMinimumADC;
	}else{
		boundedTPSADC = 0;
	}


	/* Get BRV from ADC using transfer variables (all installations need this) */
	unsigned short localBRV;
	if(TRUE){ /* If BRV connected  */
/// @todo TODO WARNING: HACK!!! Remove ASAP!!! IE, As Soon As Preston (get's a new cpu on the TA card!)
#ifdef HOTEL
		localBRV = (((unsigned long)ADCBuffers->MAT * fixedConfigs2.sensorRanges.BRVRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.BRVMinimum;
#else
		localBRV = (((unsigned long)ADCBuffers->BRV * fixedConfigs2.sensorRanges.BRVRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.BRVMinimum;
#endif
	}else if(FALSE){ /* Configured to be fixed value */
		/* Get the preferred BRV figure from configuration settings */
		localBRV = fixedConfigs2.sensorPresets.presetBRV;
	}else{ /* Fail safe if config is broken */
		/* Default to normal alternator charging voltage 14.4V */
		localBRV = VOLTS(14.4);
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(BRV_NOT_CONFIGURED_CODE);
	}


	unsigned short localCHT;
	/* Get CHT from ADC using the transfer table (all installations need this) */
	if(TRUE){ /* If CHT connected  */
		localCHT = CHTTransferTable[ADCBuffers->CHT];
	}else if(FALSE){ /* Configured to be read From ADC as dashpot */
		/* Transfer the ADC reading to an engine temperature in a reasonable way */
		localCHT = (ADCBuffers->CHT * 10) + DEGREES_C(0); /* 0 ADC = 0C = 273.15K = 27315, 1023 ADC = 102.3C = 375.45K = 37545 */
	}else if(FALSE){ /* Configured to be fixed value */
		/* Get the preferred CHT figure from configuration settings */
		localCHT = fixedConfigs2.sensorPresets.presetCHT;
	}else{ /* Fail safe if config is broken */
		/* Default to normal running temperature of 85C/358K */
		localCHT = DEGREES_C(85);
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(CHT_NOT_CONFIGURED_CODE);
	}


	unsigned short localIAT;
	/* Get IAT from ADC using the transfer table (all installations need this) */
	if(TRUE){ /* If IAT connected  */ /* using false here causes iat to default to room temp, useful with heatsoaked OEM sensors like the Volvo's... */
		localIAT = IATTransferTable[ADCBuffers->IAT];
	}else if(FALSE){ /* Configured to be read From ADC as dashpot */
		/* Transfer the ADC reading to an air temperature in a reasonable way */
		localIAT = (ADCBuffers->IAT * 10) + 27315; /* 0 ADC = 0C = 273.15K = 27315, 1023 ADC = 102.3C = 375.45K = 37545 */
	}else if(FALSE){ /* Configured to be fixed value */
		/* Get the preferred IAT figure from configuration settings */
		localIAT = fixedConfigs2.sensorPresets.presetIAT;
	}else{ /* Fail safe if config is broken */
		/* Default to room temperature (20C/293K) TODO poor choice, fix. */
		localIAT = DEGREES_C(20);
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(IAT_NOT_CONFIGURED_CODE);
	}


	unsigned short localMAT;
	/* Determine the MAT reading for future calculations */
	if(TRUE){ /* If MAT sensor is connected */
		/* Get MAT from ADC using same transfer table as IAT (too much space to waste on having two) */
		localMAT = IATTransferTable[ADCBuffers->MAT];
	}else if(FALSE){ /* Configured to be fixed value */
		/* Get the preferred MAT figure from configuration settings */
		localMAT = fixedConfigs2.sensorPresets.presetMAT;
	}else{ /* Fail safe if config is broken */
		/* If not, default to same value as IAT */
		localMAT = localIAT;
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(MAT_NOT_CONFIGURED_CODE);
	}


	unsigned short localMAP;
	unsigned short localIAP;
	/* Determine the MAP pressure to use for future calculations */
	if(TRUE){ /* If MAP sensor is connected */
		/* get MAP from ADC using transfer variables */
		localMAP = (((unsigned long)ADCBuffers->MAP * fixedConfigs2.sensorRanges.MAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.MAPMinimum;
		if(TRUE){ /* If Intercooler boost sensor connected */
			/* Get IAP from ADC using the same transfer variables as they both need to read the same range */
			localIAP = (((unsigned long)ADCBuffers->IAP * fixedConfigs2.sensorRanges.MAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.MAPMinimum;
		}
	}else if(FALSE){ /* Configured for MAP to imitate TPS signal */
		/* Get MAP from TPS via conversion */
		localMAP = (((unsigned long)boundedTPSADC * TPSMAPRange) / TPSADCRange) + fixedConfigs2.sensorRanges.TPSClosedMAP;
	}else if(FALSE){ /* Configured for dash potentiometer on ADC */
		/* Get MAP from ADC via conversion to internal kPa figure where 1023ADC = 655kPa */
		localMAP = ADCBuffers->MAP << 6;
		if(TRUE){ /* If Intercooler boost sensor enabled */
			/* Get IAP from ADC via conversion to internal kPa figure where 1023ADC = 655kPa */
			localIAP = ADCBuffers->IAP << 6;
		}
	}else if(FALSE){ /* Configured for fixed MAP from config */
		/* Get the preferred MAP figure from configuration settings */
		localMAP = fixedConfigs2.sensorPresets.presetMAP;
	}else{ /* Fail safe if config is broken */
		/* Default to zero to nulify all other calcs and effectively cut fuel */
		localMAP = 0;
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(MAP_NOT_CONFIGURED_CODE); // or maybe queue it?
	}


	/* Determine MAF variable if required */
	unsigned short localMAF = 0; // Default to zero as it is not required for anything except main PW calcs optionally
	if(TRUE){
		localMAF = MAFTransferTable[ADCBuffers->MAF];
	}

	unsigned short localAAP;
	/* Determine the Atmospheric pressure to use for future calculations */
	if(TRUE){ /* Configured for second sensor to read AAP */
		/* get AAP from ADC using separate vars to allow 115kPa sensor etc to be used */
		localAAP = (((unsigned long)ADCBuffers->AAP * fixedConfigs2.sensorRanges.AAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.AAPMinimum;
	}else if(FALSE){ /* Configured for dash potentiometer on ADC */
		/* Get AAP from ADC via conversion to internal kPa figure where 1023ADC = 102.3kPa */
		localAAP = ADCBuffers->AAP * 10;
	}else if(FALSE){ /* Configured for fixed AAP from config */
		/* Get the preferred AAP figure from configuration settings */
		localAAP = fixedConfigs2.sensorPresets.presetAAP;
	}else{ /* Fail safe if config is broken */
		/* Default to sea level */
		localAAP = KPA(100);
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(AAP_NOT_CONFIGURED_CODE); // or maybe queue it?
	}


	unsigned short localEGO;
	/* Get main Lambda reading */
	if(TRUE){ /* If WBO2-1 is connected */
		/* Get EGO from ADCs using transfer variables */
		localEGO = (((unsigned long)ADCBuffers->EGO * fixedConfigs2.sensorRanges.EGORange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.EGOMinimum;
	}else if(FALSE){ /* Configured for fixed EGO from config */
		/* Get the preferred EGO figure from configuration settings */
		localEGO = fixedConfigs2.sensorPresets.presetEGO;
	}else{ /* Default value if not connected incase other things are misconfigured */
		/* Default to stoichiometric */
		localEGO = LAMBDA(1.0);
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(EGO_NOT_CONFIGURED_CODE); // or maybe queue it?
	}


	unsigned short localEGO2;
	/* Get second Lambda reading */
	if(TRUE){ /* If WBO2-2 is connected */
		/* Get EGO2 from ADCs using same transfer variables as EGO */
		localEGO2 = (((unsigned long)ADCBuffers->EGO2 * fixedConfigs2.sensorRanges.EGORange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.EGOMinimum;
	}else if(FALSE){ /* Configured for fixed EGO2 from config */
		/* Get the preferred EGO2 figure from configuration settings */
		localEGO2 = fixedConfigs2.sensorPresets.presetEGO2;
	}else{ /* Default value if not connected incase other things are misconfigured */
		/* Default to stoichiometric */
		localEGO2 = LAMBDA(1.0);
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(EGO2_NOT_CONFIGURED_CODE); // or maybe queue it?
	}


	unsigned short localTPS;
	/* Get TPS percentage */
	if(TRUE){ /* If TPS is connected */
		/* Get TPS from ADC no need to add TPS min as we know it is zero by definition */
		localTPS = ((unsigned long)boundedTPSADC * PERCENT(100)) / TPSADCRange;
	}else if(FALSE){ /* Configured for TPS to imitate MAP signal */
		/* Get TPS from MAP via conversion */
		/* Box MAP signal down */
		if(localTPS > fixedConfigs2.sensorRanges.TPSOpenMAP){ /* Greater than ~95kPa */
			localTPS = PERCENT(100);
		}else if(localTPS < fixedConfigs2.sensorRanges.TPSClosedMAP){ /* Less than ~30kPa */
			localTPS = 0;
		}else{ /* Scale MAP range to TPS range */
			localTPS = localMAP - fixedConfigs2.sensorRanges.TPSClosedMAP;
		}
		// get TPS from MAP no need to add TPS min as we know it is zero by definition
		localTPS = ((unsigned long)localTPS * PERCENT(100)) / (fixedConfigs2.sensorRanges.TPSOpenMAP - fixedConfigs2.sensorRanges.TPSClosedMAP);
	}else if(FALSE){ /* Configured for dash potentiometer on ADC */
		/* Get TPS from ADC as shown : 1023 ADC = 100%, 0 ADC = 0% */
		localTPS = ((unsigned long)ADCBuffers->TPS * PERCENT(100)) / ADC_DIVISIONS;
	}else if(FALSE){ /* Configured for fixed TPS from config */
		/* Get the preferred TPS figure from configuration settings */
		localTPS = fixedConfigs2.sensorPresets.presetTPS;
	}else{ /* Fail safe if config is broken */
		/* Default to 50% to not trigger any WOT or CT conditions */
		localTPS = PERCENT(50); // TODO YAGNI?
		/* If anyone is listening, let them know something is wrong */
		sendErrorIfClear(TPS_NOT_CONFIGURED_CODE); // or maybe queue it?
	}


	/* Get RPM by locking out ISRs for a second and grabbing the Tooth logging data */
	//atomic start
	// copy rpm data
	//atomic end

	// Calculate RPM and delta RPM and delta delta RPM from data recorded
	if(*ticksPerDegree != 0){
		CoreVars->RPM = (unsigned short)(degreeTicksPerMinute / *ticksPerDegree);
	}else{
		CoreVars->RPM = 0;
	}

	CoreVars->DRPM = *ticksPerDegree;
//	unsigned short localDRPM = 0;
//	unsigned short localDDRPM = 0;


	/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/




	/*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Average the variables as per the configuration &&&&&&&&&&&&&&&&&&&&&&&&&&*/
	/* Strictly speaking only the primary variables need to be averaged. After that, the derived ones are	*/
	/* already averaged in a way. However, there may be some advantage to some short term averaging on the	*/
	/* derived ones also, so it is something to look into later.											*/

	/// @todo TODO average the generated values here

//			newVal var word        ' the value from the ADC
//			smoothed var word    ' a nicely smoothed result
//
//			if newval > smoothed then
//			        smoothed = smoothed + (newval - smoothed)/alpha
//			else
//			        smoothed = smoothed - (smoothed - newval)/alpha
//			endif

	// from : http://www.tigoe.net/pcomp/code/category/code/arduinowiring/41

	// for now just copy them in.
	CoreVars->IAT = localIAT;
	CoreVars->CHT = localCHT;
	CoreVars->TPS = localTPS;
	CoreVars->EGO = localEGO;
	CoreVars->BRV = localBRV;
	CoreVars->MAP = localMAP;
	CoreVars->AAP = localAAP;
	CoreVars->MAT = localMAT;

	CoreVars->EGO2 = localEGO2;
	CoreVars->IAP = localIAP;
	CoreVars->MAF = localMAF;
//	CoreVars->DRPM = localDRPM;
//	CoreVars->DDRPM = localDDRPM;
//	CoreVars->DTPS = localDTPS;

	// later...
	unsigned short i;
	for(i=0;i<sizeof(CoreVar);i++){ // TODO
		/* Perform averaging on all primary variables as per the configuration array */
		// get old value(s)
		// process new and old to produce result based on config array value */
		// assign result to old value holder
	} // TODO

	/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
}
Beispiel #24
0
/* Fire a weapon at something */
bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, int weapon_slot)
{
	WEAPON_STATS	*psStats;
	UDWORD                  damLevel;
	UDWORD			firePause;
	SDWORD			longRange;
	DROID			*psDroid = NULL;
	int				compIndex;

	CHECK_OBJECT(psAttacker);
	CHECK_OBJECT(psTarget);
	ASSERT(psWeap != NULL, "Invalid weapon pointer");

	/* Watermelon:dont shoot if the weapon_slot of a vtol is empty */
	if (psAttacker->type == OBJ_DROID && isVtolDroid(((DROID *)psAttacker)))
	{
		if (((DROID *)psAttacker)->sMove.iAttackRuns[weapon_slot] >= getNumAttackRuns(((DROID *)psAttacker), weapon_slot))
		{
			objTrace(psAttacker->id, "VTOL slot %d is empty", weapon_slot);
			return false;
		}
	}

	/* Get the stats for the weapon */
	compIndex = psWeap->nStat;
	ASSERT_OR_RETURN( false , compIndex < numWeaponStats, "Invalid range referenced for numWeaponStats, %d > %d", compIndex, numWeaponStats);
	psStats = asWeaponStats + compIndex;

	// check valid weapon/prop combination
	if (!validTarget(psAttacker, psTarget, weapon_slot))
	{
		return false;
	}

	/*see if reload-able weapon and out of ammo*/
	if (psStats->reloadTime && !psWeap->ammo)
	{
		if (gameTime - psWeap->lastFired < weaponReloadTime(psStats, psAttacker->player))
		{
			return false;
		}
		//reset the ammo level
		psWeap->ammo = psStats->numRounds;
	}

	/* See when the weapon last fired to control it's rate of fire */
	firePause = weaponFirePause(psStats, psAttacker->player);

	// increase the pause if heavily damaged
	switch (psAttacker->type)
	{
	case OBJ_DROID:
		psDroid = (DROID *)psAttacker;
		damLevel = PERCENT(psDroid->body, psDroid->originalBody);
		break;
	case OBJ_STRUCTURE:
		damLevel = PERCENT(((STRUCTURE *)psAttacker)->body, structureBody((STRUCTURE *)psAttacker));
		break;
	default:
		damLevel = 100;
		break;
	}

	if (damLevel < HEAVY_DAMAGE_LEVEL)
	{
		firePause += firePause;
	}

	if (gameTime - psWeap->lastFired <= firePause)
	{
		/* Too soon to fire again */
		return false;
	}

	// add a random delay to the fire
	// With logical updates, a good graphics gard no longer gives a better ROF.
	// TODO Should still replace this with something saner, such as a ±1% random deviation in reload time.
	int fireChance = gameTime - (psWeap->lastFired + firePause);
	if (gameRand(RANDOM_PAUSE) > fireChance)
	{
		return false;
	}

	if (psTarget->visible[psAttacker->player] != UBYTE_MAX)
	{
		// Can't see it - can't hit it
		objTrace(psAttacker->id, "combFire(%u[%s]->%u): Object has no indirect sight of target", psAttacker->id, psStats->pName, psTarget->id);
		return false;
	}

	/* Check we can see the target */
	if (psAttacker->type == OBJ_DROID && !isVtolDroid((DROID *)psAttacker)
	    && (proj_Direct(psStats) || actionInsideMinRange(psDroid, psTarget, psStats)))
	{
		if(!lineOfFire(psAttacker, psTarget, weapon_slot, true))
		{
			// Can't see the target - can't hit it with direct fire
			objTrace(psAttacker->id, "combFire(%u[%s]->%u): Droid has no direct line of sight to target",
			      psAttacker->id, ((DROID *)psAttacker)->aName, psTarget->id);
			return false;
		}
	}
	else if ((psAttacker->type == OBJ_STRUCTURE) &&
			 (((STRUCTURE *)psAttacker)->pStructureType->height == 1) &&
			 proj_Direct(psStats))
	{
		// a bunker can't shoot through walls
		if (!lineOfFire(psAttacker, psTarget, weapon_slot, true))
		{
			// Can't see the target - can't hit it with direct fire
			objTrace(psAttacker->id, "combFire(%u[%s]->%u): Structure has no direct line of sight to target",
			      psAttacker->id, ((STRUCTURE *)psAttacker)->pStructureType->pName, psTarget->id);
			return false;
		}
	}
	else if ( proj_Direct(psStats) )
	{
		// VTOL or tall building
		if (!lineOfFire(psAttacker, psTarget, weapon_slot, false))
		{
			// Can't see the target - can't hit it with direct fire
			objTrace(psAttacker->id, "combFire(%u[%s]->%u): Tall object has no direct line of sight to target",
			      psAttacker->id, psStats->pName, psTarget->id);
			return false;
		}
	}

	Vector3i deltaPos = psTarget->pos - psAttacker->pos;

	// if the turret doesn't turn, check if the attacker is in alignment with the target
	if (psAttacker->type == OBJ_DROID && !psStats->rotate)
	{
		uint16_t targetDir = iAtan2(removeZ(deltaPos));
		int dirDiff = abs(angleDelta(targetDir - psAttacker->rot.direction));
		if (dirDiff > FIXED_TURRET_DIR)
		{
			return false;
		}
	}

	/* Now see if the target is in range  - also check not too near */
	int dist = iHypot(removeZ(deltaPos));
	longRange = proj_GetLongRange(psStats);

	/* modification by CorvusCorax - calculate shooting angle */
	int min_angle = 0;
	// only calculate for indirect shots
	if (!proj_Direct(psStats) && dist > 0)
	{
		min_angle = arcOfFire(psAttacker,psTarget,weapon_slot,true);

		// prevent extremely steep shots
		min_angle = std::min(min_angle, DEG(PROJ_ULTIMATE_PITCH));

		// adjust maximum range of unit if forced to shoot very steep
		if (min_angle > DEG(PROJ_MAX_PITCH))
		{
			//do not allow increase of max range though
			if (iSin(2*min_angle) < iSin(2*DEG(PROJ_MAX_PITCH)))  // If PROJ_MAX_PITCH == 45, then always iSin(2*min_angle) <= iSin(2*DEG(PROJ_MAX_PITCH)), and the test is redundant.
			{
				longRange = longRange * iSin(2*min_angle) / iSin(2*DEG(PROJ_MAX_PITCH));
			}
		}
	}

	int baseHitChance = 0;
	if ((dist <= psStats->shortRange)  && (dist >= psStats->minRange))
	{
		// get weapon chance to hit in the short range
		baseHitChance = weaponShortHit(psStats,psAttacker->player);
	}
	else if ((dist <= longRange && dist >= psStats->minRange)
	         || (psAttacker->type == OBJ_DROID
	             && !proj_Direct(psStats)
	             && actionInsideMinRange(psDroid, psTarget, psStats)))
	{
		// get weapon chance to hit in the long range
		baseHitChance = weaponLongHit(psStats,psAttacker->player);

		// adapt for height adjusted artillery shots
		if (min_angle > DEG(PROJ_MAX_PITCH))
		{
			baseHitChance = baseHitChance * iCos(min_angle) / iCos(DEG(PROJ_MAX_PITCH));
		}
	}
	else
	{
		/* Out of range */
		objTrace(psAttacker->id, "combFire(%u[%s]->%u): Out of range", psAttacker->id, psStats->pName, psTarget->id);
		return false;
	}

	// apply experience accuracy modifiers to the base
	//hit chance, not to the final hit chance
	int resultHitChance = baseHitChance;

	// add the attacker's experience
	if (psAttacker->type == OBJ_DROID)
	{
		SDWORD	level = getDroidEffectiveLevel((DROID *) psAttacker);

		// increase total accuracy by EXP_ACCURACY_BONUS % for each experience level
		resultHitChance += EXP_ACCURACY_BONUS * level * baseHitChance / 100;
	}

	// subtract the defender's experience
	if (psTarget->type == OBJ_DROID)
	{
		SDWORD	level = getDroidEffectiveLevel((DROID *) psTarget);

		// decrease weapon accuracy by EXP_ACCURACY_BONUS % for each experience level
		resultHitChance -= EXP_ACCURACY_BONUS * level * baseHitChance / 100;

	}

	// fire while moving modifiers
	if (psAttacker->type == OBJ_DROID &&
		((DROID *)psAttacker)->sMove.Status != MOVEINACTIVE)
	{
		switch (psStats->fireOnMove)
		{
		case FOM_NO:
			// Can't fire while moving
			return false;
			break;
		case FOM_PARTIAL:
			resultHitChance = FOM_PARTIAL_ACCURACY_PENALTY * resultHitChance / 100;
			break;
		case FOM_YES:
			// can fire while moving
			break;
		}
	}

	/* -------!!! From that point we are sure that we are firing !!!------- */

	/* note when the weapon fired */
	psWeap->lastFired = gameTime;

	/* reduce ammo if salvo */
	if (psStats->reloadTime)
	{
		psWeap->ammo--;
	}

	// increment the shots counter
	psWeap->shotsFired++;

	// predicted X,Y offset per sec
	Vector3i predict = psTarget->pos;

	//Watermelon:Target prediction
	if (isDroid(psTarget))
	{
		DROID *psDroid = castDroid(psTarget);

		int32_t flightTime;
		if (proj_Direct(psStats) || dist <= psStats->minRange)
		{
			flightTime = dist / psStats->flightSpeed;
		}
		else
		{
			int32_t vXY, vZ;  // Unused, we just want the flight time.
			flightTime = projCalcIndirectVelocities(dist, deltaPos.z, psStats->flightSpeed, &vXY, &vZ, min_angle);
		}

		if (psTarget->lastHitWeapon == WSC_EMP)
		{
			int empTime = EMP_DISABLE_TIME - (gameTime - psTarget->timeLastHit);
			CLIP(empTime, 0, EMP_DISABLE_TIME);
			if (empTime >= EMP_DISABLE_TIME * 9/10)
			{
				flightTime = 0;  /* Just hit.  Assume they'll get hit again */
			}
			else
			{
				flightTime = MAX(0, flightTime - empTime);
			}
		}

		predict += Vector3i(iSinCosR(psDroid->sMove.moveDir, psDroid->sMove.speed*flightTime / GAME_TICKS_PER_SEC), 0);
	}

	/* Fire off the bullet to the miss location. The miss is only visible if the player owns the target. (Why? - Per) */
	// What bVisible really does is to make the projectile audible even if it misses you. Since the target is NULL, proj_SendProjectile can't check if it was fired at you.
	bool bVisibleAnyway = psTarget->player == selectedPlayer;

	// see if we were lucky to hit the target
	bool isHit = gameRand(100) <= resultHitChance;
	if (isHit)
	{
		/* Kerrrbaaang !!!!! a hit */
		objTrace(psAttacker->id, "combFire: [%s]->%u: resultHitChance=%d, visibility=%hhu : ", psStats->pName, psTarget->id, resultHitChance, psTarget->visible[psAttacker->player]);
		syncDebug("hit=(%d,%d,%d)", predict.x, predict.y, predict.z);
	}
	else /* Deal with a missed shot */
	{
		const int minOffset = 5;

		int missDist = 2 * (100 - resultHitChance) + minOffset;
		Vector3i miss = Vector3i(iSinCosR(gameRand(DEG(360)), missDist), 0);
		predict += miss;

		psTarget = NULL;  // Missed the target, so don't expect to hit it.

		objTrace(psAttacker->id, "combFire: Missed shot by (%4d,%4d)", miss.x, miss.y);
		syncDebug("miss=(%d,%d,%d)", predict.x, predict.y, predict.z);
	}

	// Make sure we don't pass any negative or out of bounds numbers to proj_SendProjectile
	CLIP(predict.x, 0, world_coord(mapWidth - 1));
	CLIP(predict.y, 0, world_coord(mapHeight - 1));

	proj_SendProjectileAngled(psWeap, psAttacker, psAttacker->player, predict, psTarget, bVisibleAnyway, weapon_slot, min_angle);
	return true;
}
int main(
    _In_ int argc,
    _In_ TCHAR * argv[]
    ) {
    DWORD i = 0;

    LOG(Succ, _T("Starting"));

    //
    // Options parsing
    //
    LOG(Succ, _T("Parsing options"));
    ACE_FILTER_OPTIONS options = { 0 };
    DWORD importerAce = PLUGIN_MAX_IMPORTERS;
    DWORD importerObj = PLUGIN_MAX_IMPORTERS;
    DWORD importerSch = PLUGIN_MAX_IMPORTERS;

    if (argc > 1) {
        ParseOptions(&options, argc, argv);
    }
    else {
        options.misc.showHelp = TRUE;
    }

    if (options.misc.showHelp) {
        Usage(argv[0], NULL);
        ForeachLoadedPlugins(&options, PluginHelp);
        ExitProcess(EXIT_FAILURE);
    }


    //
    // Plugins verifications
    //
    LOG(Succ, "Verifying and choosing plugins");

    if (options.plugins.numberOfImporters == 0){
        FATAL(_T("No importer has been loaded"));
    }

    if (options.plugins.numberOfWriters == 0){
        FATAL(_T("No writer has been loaded"));
    }

    for (i = 0; i < options.plugins.numberOfImporters; i++) {
        if (!PLUGIN_IS_LOADED(&options.plugins.importers[i])) {
            FATAL(_T("Importer <%u> is registered, but not loaded"), i);
        }

        if (importerAce == PLUGIN_MAX_IMPORTERS && options.plugins.importers[i].functions.GetNextAce) {
            LOG(Info, SUB_LOG(_T("Using <%s> to import ACE")), PLUGIN_GET_NAME(&options.plugins.importers[i]));
            importerAce = i;
        }

        if (importerObj == PLUGIN_MAX_IMPORTERS && options.plugins.importers[i].functions.GetNextSchema) {
            LOG(Info, SUB_LOG(_T("Using <%s> to import objects")), PLUGIN_GET_NAME(&options.plugins.importers[i]));
            importerObj = i;
        }

        if (importerSch == PLUGIN_MAX_IMPORTERS && options.plugins.importers[i].functions.GetNextObject) {
            LOG(Info, SUB_LOG(_T("Using <%s> to import schema")), PLUGIN_GET_NAME(&options.plugins.importers[i]));
            importerSch = i;
        }
    }

	if (importerAce == PLUGIN_MAX_IMPORTERS){
		FATAL(_T("ACE importer is missing"));
	}
	if (importerObj == PLUGIN_MAX_IMPORTERS){
		FATAL(_T("Obj importer is missing"));
	}
	if (importerSch == PLUGIN_MAX_IMPORTERS){
		FATAL(_T("Sch importer is missing"));
	}

    // We allow no filter to be loaded, to permit ACE format conversion (direct link importer->writer)
    if (options.plugins.numberOfFilters > 0) {
        for (i = 0; i < options.plugins.numberOfFilters; i++) {
            if (!PLUGIN_IS_LOADED(&options.plugins.filters[i])) {
                FATAL(_T("Filter <%u> is registered, but not loaded"), i);
            }
        }
    }

    for (i = 0; i < options.plugins.numberOfWriters; i++) {
        if (!PLUGIN_IS_LOADED(&options.plugins.writers[i])) {
            FATAL(_T("Writer <%u> is registered, but not loaded"), i);
        }
    }


    //
    // Initializing plugins
    //
    LOG(Succ, _T("Initializing plugins"));
    ForeachLoadedPlugins(&options, PluginInitialize);


    //
    // Constructing caches
    //
    LOG(Succ, _T("Constructing caches"));

    CachesInitialize();

    if (PluginsRequires(&options, OPT_REQ_SID_RESOLUTION) || PluginsRequires(&options, OPT_REQ_DN_RESOLUTION)) {
        LOG(Info, SUB_LOG(_T("Plugins require SID or DN resolution, constructing object cache")));
        ConstructObjectCache(&options.plugins.importers[importerObj]);
        LOG(Info, SUB_LOG(_T("Object cache count : <by-sid:%u> <by-dn:%u>")), CacheObjectBySidCount(), CacheObjectByDnCount());
    }

	if (PluginsRequires(&options, OPT_REQ_GUID_RESOLUTION) || PluginsRequires(&options, OPT_REQ_CLASSID_RESOLUTION) || PluginsRequires(&options, OPT_REQ_DISPLAYNAME_RESOLUTION)) {
        LOG(Info, SUB_LOG(_T("Plugins require GUID or CLASSID or DisplayName resolution, constructing schema cache")));
        ConstructSchemaCache(&options.plugins.importers[importerSch]);
        LOG(Info, SUB_LOG(_T("Schema cache count : <by-guid:%u> <by-classid:%u> <by-displayname:%u>")), CacheSchemaByGuidCount(), CacheSchemaByClassidCount(), CacheSchemaByDisplayNameCount());
    }

    if (PluginsRequires(&options, OPT_REQ_ADMINSDHOLDER_SD)) {
        LOG(Info, SUB_LOG(_T("Plugins require AdminSdHolder security descriptor, constructing it")));
        ConstructAdminSdHolderSD(&options.plugins.importers[importerAce]);
    }


    //
    // Main Loop : process and filter ACEs
    //
    LOG(Succ, _T("Starting ACE filtering"));

    IMPORTED_ACE ace = { 0 };
    BOOL passedFilters = TRUE;
    BOOL filterRet = FALSE;

    // Stats variables
    DWORD aceCount = 0;
    DWORD keptAceCount = 0;
    ULONGLONG timeStart = 0;

    timeStart = GetTickCount64();

    options.plugins.importers[importerAce].functions.ResetReading(&gc_PluginApiTable, ImporterAce);
    while (options.plugins.importers[importerAce].functions.GetNextAce(&gc_PluginApiTable, &ace)) {
        passedFilters = TRUE;
        ace.computed.number = ++aceCount;

        for (i = 0; i < options.plugins.numberOfFilters; i++) {

            filterRet = options.plugins.filters[i].functions.FilterAce(&gc_PluginApiTable, &ace);
            passedFilters &= options.plugins.filters[i].inverted ? !filterRet : filterRet;

            if (!passedFilters) {
                LOG(All, _T("Ace <%u> was filtered by <%s>"), aceCount, PLUGIN_GET_NAME(&options.plugins.filters[i]));
                break;
            }
        }

        if (passedFilters) {
            keptAceCount++;
            LOG(All, _T("Ace <%u> passed all filters"), aceCount);
            for (i = 0; i < options.plugins.numberOfWriters; i++) {
                options.plugins.writers[i].functions.WriteAce(&gc_PluginApiTable, &ace);
            }
        }

        if (aceCount % options.misc.progression == 0) {
            LOG(Info, SUB_LOG(_T("Count : %u")), aceCount);
        }

        FreeCheckX(ace.imported.objectDn); // TODO : possible leak, since this is importer-dependant. Call importer's destroyer instead.
        LocalFreeCheckX(ace.imported.raw);
        ZeroMemory(&ace, sizeof(IMPORTED_ACE));
    }

    //
    // Stats
    //
    LOG(Succ, _T("Done. ACE Statistics :"));
    LOG(Succ, SUB_LOG(_T("<total    : %u>")), aceCount);
    LOG(Succ, SUB_LOG(_T("<filtered : %06.2f%%  %u>")), PERCENT((aceCount - keptAceCount), aceCount), (aceCount - keptAceCount));
    LOG(Succ, SUB_LOG(_T("<kept     : %06.2f%%  %u>")), PERCENT(keptAceCount, aceCount), keptAceCount);
    LOG(Succ, SUB_LOG(_T("<time     : %.3fs>")), TIME_DIFF_SEC(timeStart, GetTickCount64()));


    //
    // Finalizing and unloading plugins
    //
    LOG(Succ, _T("Finalizing and unloading plugins"));
    ForeachLoadedPlugins(&options, PluginFinalize);
    ForeachLoadedPlugins(&options, PluginUnload);

    CachesDestroy();
    DestroyStrPairList(gs_PluginOptions.head);

    //
    // End
    //
    LOG(Succ, _T("Done"));
    return EXIT_SUCCESS;
}