double c_canberra_expected(long n, long k) { double sum = 0.0; long t; for (t=1; t<=k; t++) sum += t * (a_harm(2 * k - t) - a_harm(t)); return 2.0 / n * sum + (2.0 * (n - k) / n) * (2 * (k + 1) * (harm(2 * k + 1) - harm(k + 1)) - k); }
void LVL_Npc::doHarm(int damageReason) { int damageLevel=1; //call Lua //onHarm(killReason, out_DamageLevel) harm(damageLevel, damageReason); }
void LuaProxy::NPC::harm(short harmType, float damage, lua_State * L) { if (!isValid_throw(L)) return; // Patch all instructions which add a damage amount to the NPC auto patchSet = PatchCollection( PATCH(0xA2A2D1 + 2).dword((DWORD)&damage), PATCH(0xA2A418 + 2).dword((DWORD)&damage), PATCH(0xA2A45C + 2).dword((DWORD)&damage), PATCH(0xA2A5C5 + 2).dword((DWORD)&damage), PATCH(0xA2A5CD + 2).dword((DWORD)&damage), PATCH(0xA2A62F + 2).dword((DWORD)&damage), PATCH(0xA2A745 + 2).dword((DWORD)&damage), PATCH(0xA2A766 + 2).dword((DWORD)&damage), PATCH(0xA2A7AB + 2).dword((DWORD)&damage), PATCH(0xA2A94E + 2).dword((DWORD)&damage), PATCH(0xA2A9FC + 2).dword((DWORD)&damage), PATCH(0xA2AA3C + 2).dword((DWORD)&damage), PATCH(0xA2AB08 + 2).dword((DWORD)&damage), PATCH(0xA2AB63 + 2).dword((DWORD)&damage), PATCH(0xA2AD8E + 2).dword((DWORD)&damage), PATCH(0xA2C124 + 2).dword((DWORD)&damage), PATCH(0xA2C164 + 2).dword((DWORD)&damage), PATCH(0xA2C5B9 + 2).dword((DWORD)&damage), PATCH(0xA2C672 + 2).dword((DWORD)&damage), PATCH(0xA2C6CC + 2).dword((DWORD)&damage), PATCH(0xA2C7B7 + 2).dword((DWORD)&damage), PATCH(0xA2C826 + 2).dword((DWORD)&damage), PATCH(0xA2E1B1 + 2).dword((DWORD)&damage), PATCH(0xA2E20E + 2).dword((DWORD)&damage), PATCH(0xA2E280 + 2).dword((DWORD)&damage), PATCH(0xA2FE7F + 2).dword((DWORD)&damage), PATCH(0xA2FEC7 + 2).dword((DWORD)&damage), PATCH(0xA2FF01 + 2).dword((DWORD)&damage), PATCH(0xA2FFA7 + 2).dword((DWORD)&damage), PATCH(0xA300B2 + 2).dword((DWORD)&damage), PATCH(0xA300FA + 2).dword((DWORD)&damage), PATCH(0xA30134 + 2).dword((DWORD)&damage) ); patchSet.Apply(); harm(harmType, L); patchSet.Unapply(); }
void LuaProxy::NPC::harm(lua_State * L) { harm(HARM_TYPE_NPC, L); }
double o_harm(long n) { return harm(n) - 0.5 * harm(floor((double) n / 2.0)); }
double e_harm(long n) { return 0.5 * harm(floor((double) n / 2.0)); }
void LVL_Player::solveCollision(PGE_Phys_Object *collided) { if(!collided) return; switch(collided->type) { case PGE_Phys_Object::LVLBlock: { LVL_Block *blk= static_cast<LVL_Block*>(collided); if(blk) { if(blk->destroyed) { #ifdef COLLIDE_DEBUG qDebug() << "Destroyed!"; #endif break; } } else { #ifdef COLLIDE_DEBUG qDebug() << "Wrong cast"; #endif break; } if( ((!forceCollideCenter)&&(!collided->posRect.collideRect(posRect)))|| ((forceCollideCenter)&&(!collided->posRect.collideRectDeep(posRect, 1.0, -3.0))) ) { #ifdef COLLIDE_DEBUG qDebug() << "No, is not collidng"; #endif break; } #ifdef COLLIDE_DEBUG qDebug() << "Collided item! "<<collided->type<<" " <<collided->posRect.center().x()<<collided->posRect.center().y(); #endif if((bumpUp||bumpDown)&&(!forceCollideCenter)) { #ifdef COLLIDE_DEBUG qDebug() << "Bump? U'r dumb!"; #endif break; } // PGE_PointF c1 = posRect.center(); // PGE_RectF &r1 = posRect; // PGE_PointF cc = collided->posRect.center(); // PGE_RectF rc = collided->posRect; switch(collided->collide_player) { case COLLISION_TOP: { if(isCollideFloorToponly(collided)) { if(blk->isHidden) break; collided_bottom[(intptr_t)collided]=collided;//bottom of player if(blk->setup->lava) kill(DEAD_burn); else if(blk->setup->danger==2||blk->setup->danger==-3||blk->setup->danger==4) harm(1); #ifdef COLLIDE_DEBUG qDebug() << "Top of block"; #endif } } break; case COLLISION_ANY: { #ifdef COLLIDE_DEBUG bool found=false; #endif //*****************************Feet of player****************************/ if( (( (blk->shape==LVL_Block::shape_rect)|| (blk->shape==LVL_Block::shape_tr_bottom_left)|| (blk->shape==LVL_Block::shape_tr_bottom_right) ) && isCollideFloor(collided))|| ((blk->shape==LVL_Block::shape_tr_top_right)&&isCollideSlopeFloor(collided, SLOPE_RIGHT)) || ((blk->shape==LVL_Block::shape_tr_top_left)&&isCollideSlopeFloor(collided, SLOPE_LEFT)) ){ if(blk->isHidden) break; collided_bottom[(intptr_t)collided]=collided;//bottom of player if(blk->setup->lava) kill(DEAD_burn); else if(blk->setup->danger==2||blk->setup->danger==-3||blk->setup->danger==4) harm(1); } //*****************************Head of player****************************/ else if( (( (blk->shape==LVL_Block::shape_rect)|| (blk->shape==LVL_Block::shape_tr_top_left)|| (blk->shape==LVL_Block::shape_tr_top_right)) && isCollideCelling(collided, _heightDelta, forceCollideCenter))|| ((blk->shape==LVL_Block::shape_tr_bottom_right)&&isCollideSlopeCelling(collided, SLOPE_RIGHT)) || ((blk->shape==LVL_Block::shape_tr_bottom_left)&&isCollideSlopeCelling(collided, SLOPE_LEFT)) ) { collided_top[(intptr_t)collided]=collided;//top of player if(blk->setup->lava) kill(DEAD_burn); else if(blk->setup->danger==-2||blk->setup->danger==-3||blk->setup->danger==4) harm(1); } //*****************************Left****************************/ else if( (isCollideLeft(collided)&&(blk->shape==LVL_Block::shape_rect))|| (isCollideLeft(collided)&&(blk->shape==LVL_Block::shape_tr_top_left) &&(posRect.bottom()>=(collided->posRect.top()+SL_HeightTopRight(collided)+1.0)))|| (isCollideLeft(collided)&&(blk->shape==LVL_Block::shape_tr_bottom_left) &&(posRect.top()<=(collided->posRect.bottom()-SL_HeightTopRight(collided)-1.0))) ) { if(blk->isHidden) break; collided_left[(intptr_t)collided]=collided;//right of player if(blk->setup->lava) kill(DEAD_burn); else if(blk->setup->danger==-1||blk->setup->danger==3||blk->setup->danger==4) harm(1); } //*****************************Right****************************/ else if( (isCollideRight(collided)&&(blk->shape==LVL_Block::shape_rect))|| (isCollideRight(collided)&&(blk->shape==LVL_Block::shape_tr_top_right) &&(posRect.bottom()>=(collided->posRect.top()+SL_HeightTopLeft(collided)+1.0)))|| (isCollideRight(collided)&&(blk->shape==LVL_Block::shape_tr_bottom_right) &&(posRect.top()<=(collided->posRect.bottom()-SL_HeightTopLeft(collided)-1.0))) ) { if(blk->isHidden) break; collided_right[(intptr_t)collided]=collided;//left of player if(blk->setup->lava) kill(DEAD_burn); else if(blk->setup->danger==1||blk->setup->danger==3||blk->setup->danger==4) harm(1); } float c=forceCollideCenter? 0.0f : 1.0f; //*****************************Center****************************/ if( ((!forceCollideCenter && blk->shape==LVL_Block::shape_rect)||(forceCollideCenter)) && blk->posRect.collideRectDeep(posRect, fabs(_velocityX_prev+_velocityX_add)*c+c*2.0, fabs(_velocityY_prev+_velocityY_add)*c+c*2.0) ) { if(blk->isHidden && !forceCollideCenter) break; collided_center[(intptr_t)collided]=collided; } break; } default: break; } break; } case PGE_Phys_Object::LVLWarp: { contactedWarp = static_cast<LVL_Warp*>(collided); if(contactedWarp) contactedWithWarp=true; break; } case PGE_Phys_Object::LVLBGO: { LVL_Bgo *bgo= static_cast<LVL_Bgo*>(collided); if(bgo) { if(bgo->setup->climbing) { bool set=climbable_map.isEmpty(); climbable_map[(intptr_t)collided]=collided; if(set) climbableHeight=collided->posRect.top(); else if(collided->top()<climbableHeight) climbableHeight=collided->top(); } } break; } case PGE_Phys_Object::LVLNPC: { LVL_Npc *npc= static_cast<LVL_Npc*>(collided); if(npc) { if(npc->isKilled()) break; if(!npc->data.msg.isEmpty()) { collided_talkable_npc=npc; } if(npc->data.friendly) break; if(npc->isGenerator) break; if(npc->setup->climbable) { bool set=climbable_map.isEmpty(); climbable_map[(intptr_t)collided]=collided; if(set) climbableHeight=collided->posRect.top(); else if(collided->top()<climbableHeight) climbableHeight=collided->top(); } if((!npc->data.friendly)&&(npc->setup->takable)) { collided_talkable_npc=NULL; npc->doHarm(LVL_Npc::DAMAGE_TAKEN); kill_npc(npc, LVL_Player::NPC_Taked_Coin); } if( ((!forceCollideCenter)&&(!collided->posRect.collideRect(posRect)))|| ((forceCollideCenter)&&(!collided->posRect.collideRectDeep(posRect, 1.0, -3.0))) ) { break; } if((bumpUp||bumpDown)&&(!forceCollideCenter)) break; if(!npc->isActivated) break; //PGE_PointF c1 = posRect.center(); //PGE_RectF &r1 = posRect; //PGE_PointF cc = collided->posRect.center(); //PGE_RectF rc = collided->posRect; switch(collided->collide_player) { case COLLISION_TOP: { if(isCollideFloorToponly(collided)) { collided_bottom[(intptr_t)collided]=collided;//bottom of player #ifdef COLLIDE_DEBUG qDebug() << "Top of block"; #endif } else { if( npc->posRect.collideRect(posRect)) { if(npc->setup->hurt_player & !npc->setup->kill_on_jump) harm(1); } } } break; case COLLISION_ANY: { #ifdef COLLIDE_DEBUG bool found=false; #endif //double xSpeed = Maths::max(fabs(speedX()+_velocityX_add), fabs(_velocityX_prev+_velocityX_add)) * Maths::sgn(speedX()+_velocityX_add); //double ySpeed = Maths::max(fabs(speedY()+_velocityY_add), fabs(_velocityY_prev+_velocityY_add)) * Maths::sgn(speedY()+_velocityY_add); //*****************************Feet of player****************************/ if(isCollideFloor(collided)) { collided_bottom[(intptr_t)collided]=collided;//bottom of player #ifdef COLLIDE_DEBUG qDebug() << "Top of block"; found=true; #endif } //*****************************Head of player****************************/ else if( isCollideCelling(collided, _heightDelta, forceCollideCenter) ) { collided_top[(intptr_t)collided]=collided;//top of player if(npc->setup->hurt_player) harm(1); #ifdef COLLIDE_DEBUG qDebug() << "Bottom of block"; found=true; #endif } //*****************************Left****************************/ else if( isCollideLeft(collided) ) { collided_left[(intptr_t)collided]=collided;//right of player if(npc->setup->hurt_player) harm(1); #ifdef COLLIDE_DEBUG qDebug() << "Right of block"; #endif } //*****************************Right****************************/ else if( isCollideRight(collided) ) { collided_right[(intptr_t)collided]=collided;//left of player if(npc->setup->hurt_player) harm(1); #ifdef COLLIDE_DEBUG qDebug() << "Left of block"; found=true; #endif } float c=forceCollideCenter? 0.0f : 1.0f; //*****************************Center****************************/ #ifdef COLLIDE_DEBUG qDebug() << "block" <<posRect.top()<<":"<<blk->posRect.bottom() << "block" <<posRect.bottom()<<":"<<blk->posRect.top()<<" collide?"<< blk->posRect.collideRectDeep(posRect, fabs(_velocityX_prev)*c+c*2.0, fabs(_velocityY_prev)*c+c*2.0) << "depths: "<< fabs(_velocityX_prev)*c+c*2.0 << fabs(_velocityY_prev)*c+c; #endif if( npc->posRect.collideRectDeep(posRect, fabs(_velocityX_prev)*c+c*2.0, fabs(_velocityY_prev)*c+c*2.0) ) { if(npc->setup->hurt_player) harm(1); if(!forceCollideCenter) break; collided_center[(intptr_t)collided]=collided; #ifdef COLLIDE_DEBUG qDebug() << "Center of block"; found=true; #endif } #ifdef COLLIDE_DEBUG qDebug() << "---checked---" << (found?"and found!": "but nothing..." )<< r1.left()<< "<="<< rc.right()<<"+"<<xSpeed ; #endif break; } case COLLISION_NONE: { //Detect top of stompable NPC! if(!npc->setup->kill_on_jump) { if( npc->posRect.collideRect(posRect)) { if(npc->setup->hurt_player) harm(1); } break; } // PGE_RectF &r1=posRect; // PGE_RectF rc = collided->posRect; // float summSpeedY=(speedY()+_velocityY_add)-(collided->speedY()+collided->_velocityY_add); // float summSpeedYprv=_velocityY_prev-collided->_velocityY_prev; if(isCollideFloorToponly(collided)) // ( // (summSpeedY >= 0.0) // && // (r1.bottom() < rc.top()+summSpeedYprv) // && // ( // (r1.left()<rc.right()-1 ) && // (r1.right()>rc.left()+1 ) // ) // ) // || // (r1.bottom() <= rc.top()) // ) { npc->doHarm(LVL_Npc::DAMAGE_STOMPED); this->bump(true); //Reset floating state floating_timer = floating_maxtime; if(floating_isworks) { floating_isworks=false; setGravityScale(climbing?0:physics_cur.gravity_scale); } kill_npc(npc, NPC_Stomped); } else { if( npc->posRect.collideRect(posRect)) { //The second half of this "if" statement is there to fix a bug with falling collisions, //and should NOT remain here because it is not how we should handle this! //The bug occurs when the player is moving fast enough when they land on an enemy that they //partially enter the enemy before the collision is resolved, causing the engine to think //that the player is INSIDE the NPC, when they are actually only JUMPING on the NPC. if(npc->setup->hurt_player & (!npc->setup->kill_on_jump || colliding_ySpeed > -1.0f)) harm(1); } } break; }//case COLLISION_NONE default: break; } } break; } case PGE_Phys_Object::LVLPhysEnv: { LVL_PhysEnv *env= static_cast<LVL_PhysEnv*>(collided); if(env) { if(env) environments_map[(intptr_t)env]=env->env_type; } break; } default: break; } }