segunda-feira, 2 de abril de 2012

void CLightmapMgr::Create(CGndRes*)

void CLightmapMgr::Create(CGndRes *gnd)
{
CLMInfo lminfo;
int surfaceId;
int i,j;
int u,v;
float u0,v0;
float u1,v1;
int row,col;
int buffer[256 * 256];
int* pPixel;
char* pAlpha;
char* pColor;
CLightmap* pLightmap;
CTexture* pTexture;

this->m_lightmaps.erase();
this->m_lmSurfaces.erase();

this->m_numLightmaps = gnd->m_numLightmap;
this->m_lightmaps.resize(this->m_numLightmaps);

this->m_numLmSurfaces = (lightmapMgr->m_numLightmaps + 1023) / 1024;
this->m_lmSurfaces.reserve(this->m_numLmSurfaces);

for( i = 0; i < this->m_numLightmaps; i += 1024 )
{
surfaceId = i / 1024;
for( j = 0; i + j < this->m_numLightmaps && j < 1024 ; ++j )
{
gnd->GetLMInfo(i + j, &lminfo);
pLightmap = &this->m_lightmaps[i];
u = (i + j - (surfaceId * 1024)) / 32;
v = (i + j - (surfaceId * 1024)) % 32;
pPixel = &buffer[(u + v * 256) * 32];
pAlpha = &lminfo.idata[0][0];
pColor = &lminfo.sdata[0][0];
for( row = 8; row > 0; --row )
{
for( col = 0; col < 8; ++col )
{
pPixel[col] = (int)((unsigned char)pColor[2]
+ (((unsigned char)pColor[1]
+ (((unsigned char)pColor[0] + ((unsigned char)*pAlpha) << 8)) << 8)) << 8);
pColor += 3;
pAlpha += 1;
}
pPixel += 256;
}
u0 = (8 * u + 1) * (1 / 256.0);
v0 = (8 * v + 1) * (1 / 256.0);
u1 = (8 * u + 7) * (1 / 256.0);
v1 = (8 * v + 7) * (1 / 256.0);
if( u0 <= 0.0 ) u0 = 0.0;
else if( u0 >= 1.0 ) u0 = 1.0;
if( v0 <= 0.0 ) v0 = 0.0;
else if( v0 >= 1.0 ) v0 = 1.0;
if( u1 <= 0.0 ) u1 = 0.0;
else if( u1 >= 1.0 ) u1 = 1.0;
if( v1 <= 0.0 ) v1 = 0.0;
else if( v1 >= 1.0 ) v1 = 1.0;
pLightmap->coor[0].u = u0;
pLightmap->coor[0].v = v0;
pLightmap->coor[1].u = u1;
pLightmap->coor[1].v = v0;
pLightmap->coor[2].u = u0;
pLightmap->coor[2].v = v1;
pLightmap->coor[3].u = u1;
pLightmap->coor[3].v = v1;
pLightmap->brightObj[0] = lminfo.sdata[4][4][0];
pLightmap->brightObj[1] = lminfo.sdata[4][4][1];
pLightmap->brightObj[2] = lminfo.sdata[4][4][2];
pLightmap->intensity[0].a = lminfo.idata[1][1];
pLightmap->intensity[0].r = lminfo.sdata[1][1][0];
pLightmap->intensity[0].g = lminfo.sdata[1][1][1];
pLightmap->intensity[0].b = lminfo.sdata[1][1][2];
pLightmap->intensity[1].a = lminfo.idata[1][5];
pLightmap->intensity[1].r = lminfo.sdata[1][5][0];
pLightmap->intensity[1].g = lminfo.sdata[1][5][1];
pLightmap->intensity[1].b = lminfo.sdata[1][5][2];
pLightmap->intensity[2].a = lminfo.idata[5][1];
pLightmap->intensity[2].r = lminfo.sdata[5][1][0];
pLightmap->intensity[2].g = lminfo.sdata[5][1][1];
pLightmap->intensity[2].b = lminfo.sdata[5][1][2];
pLightmap->intensity[3].a = lminfo.idata[5][5];
pLightmap->intensity[3].r = lminfo.sdata[5][5][0];
pLightmap->intensity[3].g = lminfo.sdata[5][5][1];
pLightmap->intensity[3].b = lminfo.sdata[5][5][2];
}
pTexture = g_texMgr.CreateTexture(256, 256, &buffer, PF_A4R4G4B4, 0);
this->m_lmSurfaces.push_back(pTexture);
}
for( i = 0; i < this->m_numLightmaps; ++i )
{
surfaceId = i / 1024;
this->m_lightmaps[i].surface = this->m_lmSurfaces[surfaceId];
}
}

quinta-feira, 13 de outubro de 2011

void CSoundMaker::SendMsg(CGameObject*,int,int,int,int)

void CSoundMaker::SendMsg(CGameObject* sender, int message, int arg1, int arg2, int arg3)
{
switch( message )
{
default:
this->CRenderObject::SendMsg(sender,message,arg1,arg2,arg3);
return;
case 0xE:
{
C3dWorldRes::soundSrcInfo* sound = (C3dWorldRes::soundSrcInfo*)arg1;
m_waveName = sound->waveName;// std::string <- char[80]
m_vol = sound->vol;// float <- float
m_width = sound->width;// int <- int
m_height = sound->height;// int <- int
m_pos.x = sound->pos.x;// float <- float
m_pos.y = sound->pos.y;// float <- float
m_pos.z = sound->pos.z;// float <- float
m_diagonal = sqrt(m_width*m_width + m_height*m_height);// float
m_cycle = ftol(sound->cycle*1000.0f);
m_lastPlayTime = timeGetTime() - m_cycle;
return;
}
}
}

void CSoundMaker::OnProcess()

// FUNC: float CRenderObject::CalcDist(float x, float y);
// FUNC: PlayWave(const char *waveFileName, float x, float y, float z, int volumeMaxDist, int volumeMinDist, float vFactor);
// VAR: float CSoundMaker::m_diagonal = sqrt(m_width*m_width + m_height*m_height);
void CSoundMaker::OnProcess()
{
CPlayer* player = g_modeMgr.GetGameMode()->m_world->m_player;
if( CalcDist(player->m_pos.x,player->m_pos.z) - (m_diagonal+m_range) <= 130.0f )
{// passed circular range
float dist_x = player.m_pos.x - m_pos.x
float dist_z = player.m_pos.z - m_pos.z
float sign_x = (dist_x >= 0.0f)? 1.0f: -1.0f;
float sign_z = (dist_z >= 0.0f)? 1.0f: -1.0f;
float cZ = dist_z / dist_x;
float todo_x;
float todo_z;
if( (double)abs(cZ) <= (double)(m_height / m_width) )
{// TODO it's probably getting the point in the elipse for the direction between this soundmaker and the player
todo_x = m_width * sign_x * 0.5;
todo_z = todo_x * cZ;
}
else
{
todo_z = m_height * sign_z * 0.5;
todo_x = todo_z / cZ;
}
float point_x = todo_x + m_pos.x;
float point_z = todo_z + m_pos.y;
if( player->CalcDist(point_x,point_z) - m_range <= 75.0f && m_waveName.length() > 0 && timeGetTime() > m_lastPlayTime + m_cycle )
{// TODO passed elliptic range?
m_lastPlayTime = timeGetTime();
float x = point_x - player->m_pos.x;
float y = 0.0f;
float z = point_z - player->m_pos.z;
int volumeMaxDist = ftol(m_range);
int volumeMinDist = ftol(m_range*(1.0f/6.0f));
float vFactor = m_vol;
PlayWave(m_waveName.c_str(),x,y,z,volumeMaxDist,volumeMinDist,vFactor);
}
}
}

sábado, 31 de outubro de 2009

Floating point comparison

float left, right;
unsigned char res = 0;
__asm push eax;
__asm fld [right];
__asm fld [left];
__asm fcompp;
__asm fnstsw ax;
__asm mov [res], ah;
__asm pop eax



left | right | ah | op
------+-------+------+---------------
-1.0 | 0.0 | 0x01 | left < right
0.0 | 0.0 | 0x40 | left == right
1.0 | 0.0 | 0x00 | left > right

terça-feira, 12 de maio de 2009

AttackMotionTime (players, homuns, npcs)

for players: CPC::UpdateAttackMotionTime()
CITP* equipedWeapon = this->m_pcItemInventoryMgr.GetITPEquipedWeapon();
CITP* other = g_itpMgr.GetITP(this->m_pcItemInventoryMgr.GetEquipedItem(0x20)->itemid);
int attackSpeed;
// initialize attackSpeed
if( equipedWeapon )
{
if( other && other->GetType() == ITPTYPE_WEAPON )// two weapons (dual)
attackSpeed = ftol(
( (float)g_charMTInfo.GetAttackMT(m_jobClass,other->GetClass())+
(float)g_charMTInfo.GetAttackMT(m_jobClass,equipedWeapon->GetClass())
)/2.0*1.4);
else// right weapon
attackSpeed = g_charMTInfo.GetAttackMT(m_jobClass,equipedWeapon->GetClass());
}
else
{
if( other && other->GetType() == ITPTYPE_WEAPON )// left weapon
attackSpeed = g_charMTInfo.GetAttackMT(m_jobClass,other->GetClass());
else// no weapon (fists)
attackSpeed = g_charMTInfo.GetAttackMT(m_jobClass,0);
}
attackSpeed -= attackSpeed*GetAgiValue()/250 + attackSpeed*GetDexValue()/1000;
if( (m_effectState&EFFECTSTATE_RIDING) != 0 )
attackSpeed += 1000 - (KN_CAVALIERMASTERY.level*10+50)*1000/100;
attackSpeed -= -m_plusAttackSpeed*10;
{// percent bonuses
int percent = CPC::GetAttackSlowValue();
percent += CPC::GetAttackHasteValue1();
percent += CPC::GetAttackHasteValue2();
if( this->m_charBuff )
percent += this->m_charBuff.GetParameterValue(PARAM_PLUS_ASPD_PERCENT);
if( GetEffective(EFST_BERSERK,0) )
percent += 30;
attackSpeed += attackSpeed*percent*17/800;// wtf??? what kind of weird percent is this?
}
// other bonuses
if( m_isSpellCasting )
attackSpeed += attackSpeed*(10-SA_FREECAST.level)*5/100;
if( GetEffective(EFST_DEFENDER,0) )
attackSpeed += (5-GetEffective(EFST_DEFENDER,0))*50;
if( equipedWeapon && equipedWeapon->GetClass() == 15 )// book?
attackSpeed += -SA_ADVANCEDBOOK.level*val*5/1000;
if( attackSpeed < 100 )
attackSpeed = 100;
this->m_attackMotionTime = attackSpeed;
this->m_pcClientUpdater.NotifyParameter(PARAM_ATTACK_MOTION_TIME/*0x35*/,0);


for homuns: CNpcHomun::GetATKTime_Client()
int attackSpeed = this->m_rechargeTime;
attackSpeed -= attackSpeed*GetAgiValue()/250 + m_rechargeTime*GetDexValue()/1000;
if( attackSpeed < 100 )
attackSpeed = 100;
attackSpeed += attackSpeed*(CNPC::GetATKHasteVal2() + CNPC::GetAttackSlowValue())*17/800;
if( attackSpeed < 100 )
attackSpeed = 100;
return attackSpeed ;


for other npcs: CNPC::UpdateParameterValue(VAR_ASPD,amount)
MONPARAMETER* monster = g_monParameter.GetMonParameter(this->m_spriteType);// m_spriteType is class
if( monster == NULL )
this->m_attackSpeed = 100;
else
{
int attackSpeed = monster->attackMT;
int percent = CNPC::GetATKHasteVal2() + CNPC::GetAttackSlowValue() + CNPC::GetATKHasteVal1()
if( this->m_charBuff )
percent += this->m_charBuff.GetParameterValue(PARAM_PLUS_ASPD_PERCENT);// 0xa7, VAR_PLUSASPDPERCENT
attackSpeed = attackSpeed*percent*17/800;
if( attackSpeed < 100 )
attackSpeed = 100;
this->m_attackSpeed = attackSpeed;
}


-------------------- (auxiliary functions) --------------------


CPC::GetAttackSlowValue()
int val[6];
memset(val, 0, sizeof(val));
val[0] = -GetEffective(EFST_DONTFORGETME,0);
val[1] = (GetEffective(EFST_STEELBODY,0) ? -25 : 0);
if( GetEffective(EFST_JOINTBEAT,0)&2 != 0 )
val[2] -= 25;
if( GetEffective(EFST_JOINTBEAT,0)&4 != 0 )
val[2] -= 10;
val[3] = (GetEffective(EFST_SLOWDOWN,0) ? -75 : 0);
val[4] = -GetEffective(EFST_GRAVITATION,0);
val[5] = -GetEffective(EFST_LONGING,1);
return min_of(val);


CPC::GetAttackHasteValue1()
if( GetEffective(EFST_ATTHASTE_INFINITY,0) )
return GetEffective(EFST_ATTHASTE_INFINITY,0);
if( GetEffective(EFST_ATTHASTE_POTION3,0) )
return GetEffective(EFST_ATTHASTE_POTION3,0);
if( GetEffective(EFST_ATTHASTE_POTION2,0) )
return GetEffective(EFST_ATTHASTE_POTION2,0);
if( GetEffective(EFST_ATTHASTE_POTION1,0) )
return GetEffective(EFST_ATTHASTE_POTION1,0);
return 0;


CPC::GetAttackHasteValue2()
int val[10];
memset(val, 0, sizeof(val));
val[0] = GetEffective(EFST_TWOHANDQUICKEN,0);
val[1] = GetEffective(EFST_SPEARQUICKEN,0);
val[2] = GetEffective(EFST_ONEHANDQUICKEN,0);
val[3] = GetEffective(EFST_ADRENALINE,0);
val[4] = GetEffective(EFST_ADRENALINE2,0);
val[5] = GetEffective(EFST_ASSASSINCROSS,0);
val[6] = GetEffective(EFST_STAR_COMFORT,0) + GetEffective(EFST_DEVIL1,0);
val[7] = GetEffective(EFST_GS_GATLINGFEVER,0) + GetEffective(EFST_GS_MADNESSCANCEL,0);
val[8] = GetEffective(EFST_PSPEED,0);
val[9] = 0;
return max_of(val);


CNPC::GetAttackSlowValue()
int val[5];
memset(val, 0, sizeof(val));
val[0] = -GetEffective(EFST_DONTFORGETME,0);
val[1] = (GetEffective(EFST_STEELBODY,0) ? -25 : 0);
if( GetEffective(EFST_JOINTBEAT,0)&2 != 0 )
val[2] -= 25;
if( GetEffective(EFST_JOINTBEAT,0)&4 != 0 )
val[2] -= 10;
val[3] = (GetEffective(EFST_SLOWDOWN,0) ? -75 : 0);
val[4] = -GetEffective(EFST_GRAVITATION,0);
return min_of(val);


CNPC::GetATKHasteVal1()
if( GetEffective(EFST_ATTHASTE_POTION3,0) )
return GetEffective(EFST_ATTHASTE_POTION3,0);
if( GetEffective(EFST_ATTHASTE_POTION2,0) )
return GetEffective(EFST_ATTHASTE_POTION2,0);
if( GetEffective(EFST_ATTHASTE_POTION1,0) )
return GetEffective(EFST_ATTHASTE_POTION1,0);
return 0;


CNPC::GetATKHasteVal2()
int val[5];
memset(val, 0, sizeof(val));
val[0] = GetEffective(EFST_ATTHASTE_INFINITY,0);
val[1] = GetEffective(EFST_ADRENALINE,0);
val[2] = GetEffective(EFST_TWOHANDQUICKEN,0);
val[3] = GetEffective(EFST_HFLI_FLEET,0);
val[4] = 0;
return max_of(val);

quinta-feira, 7 de maio de 2009

Agit

castle defense points affect guardians and emperium like this:
* maxHp += defense*1000;
* def += (defense+2)/3;
* mdef += (defense+2)/3;
GD_GUARDUP gives level*9 ATKPercent and level*4 EFST_ATTHASTE_INFINITY
there are economy/5+4 treasures
castle state is saved every 600 seconds
payTime is triggered every 10 days, but doesn't do anything (maybe on other types of servers)

// script functions:
AgitEmblemFlag "" // registers the npc as a flag of the target agit map
AgitFunc // executes a task depending on the arguments
AgitGet // gets a property of this agit map (supports all)
AgitGet2 "" // gets a property of an agit map (supports 8,9,10,11; others use the current map instead)
AgitNpcGet // gets a property of an agit npc (supports all)
AgitNpcSet // sets a property of an agit npc (supports 0,2,4)
AgitRegister "" // registers the current npc as belonging to the castle in the target map (must be a flag, class 722)
AgitSet // sets a property of this agit map

// AgitEmblemFlag vs AgitRegister:
// these seam to do the same thing, but stores them in different places
// therefore i'm assuming AgitEmblemFlag is for agit maps in another zone and AgitRegister for agit maps in this zone
// AgitEmblemFlag adds the npc to:
// static map CAgitMapRes::ms_agitTable;// mapname -> FLAG_INFO*{int guildId; char agitName[24]; vector flags;}
// AgitRegister adds the npc to:
// vector CAgitMapRes::m_flags;

// AgitFunc arguments:
// // increases triggerE (if it still can)
// // increases triggerD (if it still can)
// // sets payTime to 10 days from now
// // if( map.IsSiegeTime() ) flush target guild (or all if 0) except the owner guild;
// // refreshes the effects of castle defense and GD_GUARDUP

// AgitGet/AgitGet2/AgitSet
// -----
// agit map properties:
// 0=economy value
// 1=economy condition (if it can invest)
// 2=economy invest money (for next invest)
// 3=economy triggerE (delayed points)
// 4=defense value
// 5=defense condition (if it can invest)
// 6=defense invest money (for next invest)
// 7=defense triggerD (delayed points)
// 8=guildId
// 9=agitName
// 10=(some kind of name in the guild: guild name or owner name)
// 11=(some kind of name in the guild: guild name or owner name)
// 12=level of GD_KAFRACONTRACT
// 13=level of GD_GUARDRESEARCH
// 14=(nothing)
// 15=(unknown flag related to OnChangeOwner)
// 16=killerName (who killed the emperium)

// AgitNpcGet/AgitNpcSet
// -----
// agit npc indexes:
// 0=manager
// 1=emperium
// 2=kafra
// 100+?=guardian[?] (up to 8 guardians)
// -----
// agit npc properties:
// 0=enabled
// 1=maxHp
// 2=hp
// 3=maxHp/3 (purpose is unknown)
// 4=sp
// 5=accountName (mob name)

segunda-feira, 18 de fevereiro de 2008

Integer Division

Some divisions are optimized into a multiplication and a shift.
The result of the mul operation is in two combined registers [edx:eax].
The value of edx is result/0xFFFFFFFF.
This optimization takes advantage of that fact:
(value*multiply/0xFFFFFFFF)>>shift =>; value*original

A multiplication followed by a division is sometimes optimized the same way.

MultiplyShiftOriginal
0x069C16BD0665/25756
0x10624DD341/250
0x10624DD351/500
0x10624DD361/1000
0x2AAAAAAB01/6
0x30C30C3131/42
0x38E38E3911/9
0x4EC4EC4F31/26
0x51EB851F51/100
0x5555555601/3
0x6666666711/5
0x6666666721/10
0x6666666731/20
0x6666666741/40
0x6666666751/80
0x6666666761/160
0x6666666771/320
0x6666666781/640
0x6BCA1AF351/76
0x8888888981/480
0x9249249331/14
0xA0A0A0A171/204
0xAAAAAAAB11/3
0xAAAAAAAB21/6
0xAAAAAAAB31/12
0xAAAAAAAB41/24
0xAE147AE1517/800
0xB21642C951/46
0xB60B60B751/45
0xBA2E8BA331/11
0xEA0EA0EB032/35

Note: these optimization are only used if the resulting value doesn't lose precision in comparison to the original operation.