void CAdActor::InitLine(CBPoint StartPt, CBPoint EndPt) { m_PFCount = max( (abs(EndPt.x - StartPt.x)) , (abs(EndPt.y - StartPt.y)) ); m_PFStepX = (double)(EndPt.x - StartPt.x) / m_PFCount; m_PFStepY = (double)(EndPt.y - StartPt.y) / m_PFCount; m_PFX = StartPt.x; m_PFY = StartPt.y; int angle = (int)(atan2((double)(EndPt.y - StartPt.y), (double)(EndPt.x - StartPt.x)) * (180/3.14)); m_NextState = STATE_FOLLOWING_PATH; TurnTo(AngleToDirection(angle)); }
// Used to update view angles to stay on a ladder float StayOnLadderLine(CCSBot *me, const CNavLadder *ladder) { // determine our facing NavDirType faceDir = AngleToDirection(me->pev->v_angle.y); const float stiffness = 1.0f; // move toward ladder mount point switch (faceDir) { case NORTH: return (stiffness * (ladder->m_top.x - me->pev->origin.x)); case EAST: return (stiffness * (ladder->m_top.y - me->pev->origin.y)); case SOUTH: return (-stiffness * (ladder->m_top.x - me->pev->origin.x)); case WEST: return (-stiffness * (ladder->m_top.y - me->pev->origin.y)); } return 0.0f; }
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX window_class = {}; window_class.cbSize = sizeof(window_class); window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.lpfnWndProc = WindowCallback; window_class.hInstance = hInstance; window_class.hCursor = LoadCursor(NULL, IDC_ARROW); window_class.lpszClassName = "WCPetroCanada"; RegisterClassEx(&window_class); HWND window = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "WCPetroCanada", "Game :)", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, NULL, NULL, hInstance, NULL); ShowWindow(window, nCmdShow); UpdateWindow(window); RECT client_rect = {}; GetClientRect(window, &client_rect); Framebuffer backbuffer = {}; backbuffer.width = client_rect.right; backbuffer.height = client_rect.bottom; backbuffer.pixels = (uint32_t *)VirtualAlloc(NULL, backbuffer.width * backbuffer.height * sizeof(uint32_t ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); HDC window_context = GetDC(window); BITMAPINFO bitmap_info = {}; bitmap_info.bmiHeader.biSize = sizeof(bitmap_info); bitmap_info.bmiHeader.biWidth = backbuffer.width; bitmap_info.bmiHeader.biHeight = backbuffer.height; bitmap_info.bmiHeader.biPlanes = 1; bitmap_info.bmiHeader.biBitCount = 32; bitmap_info.bmiHeader.biCompression = BI_RGB; LoadedBitmap player_head = LoadBitmap("petro.bmp"); MSG message; bool open = true; Vector2 velocity = V2(0, 0); Vector2 position = V2(200, 200); float timestep = 1.0f; //TODO proper timestep EntityArray entities = {}; Entity *player_entity = MakeEntity(&entities, EntityType_Player, V2(200, 200), player_head.width, player_head.height, V2(10, 10)); MakeEntity(&entities, EntityType_Box, V2(50, 50), 100, 100); bool w_down = false; bool a_down = false; bool s_down = false; bool d_down = false; bool q_down = false; while(open) { while(PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) { if(message.message == WM_QUIT) { open = false; } else if(message.message == WM_KEYDOWN) { if(message.wParam == W_KEY_CODE) { w_down = true; } else if(message.wParam == S_KEY_CODE) { s_down = true; } else if(message.wParam == D_KEY_CODE) { d_down = true; } else if(message.wParam == A_KEY_CODE) { a_down = true; } else if(message.wParam == Q_KEY_CODE) { q_down = true; } } else if(message.message == WM_KEYUP) { if(message.wParam == W_KEY_CODE) { w_down = false; } else if(message.wParam == S_KEY_CODE) { s_down = false; } else if(message.wParam == D_KEY_CODE) { d_down = false; } else if(message.wParam == A_KEY_CODE) { a_down = false; } else if(message.wParam == Q_KEY_CODE) { q_down = false; } } TranslateMessage(&message); DispatchMessage(&message); } DrawRectangle(0, 0, backbuffer.width, backbuffer.height, backbuffer, V4(0.0f, 0.0f, 0.0f, 1.0f)); DrawRectangle(100, 100, 100, 100, backbuffer, V4(position.x / (float)backbuffer.width, position.y / (float)backbuffer.height, 0.0f, 1.0f)); DrawRectangle(100, 100, 150, 150, backbuffer, V4(0.0f, 1.0f, 0.0f, 0.25f)); for(int i = 0; i < entities.count; i++) { Entity *entity = entities.entities + i; if(entity->type != EntityType_Invalid) { Vector2 acceleration = V2(0, 0); if(entity == player_entity) { float multiplier = 1.0f; if(w_down) { acceleration = acceleration + V2(0, 1); } if(s_down) { acceleration = acceleration + V2(0, -1); } if(d_down) { acceleration = acceleration + V2(1, 0); } if(a_down) { acceleration = acceleration + V2(-1, 0); } if(q_down) { multiplier = 5.0f; } if(Length(acceleration) > 0) { acceleration = Normalize(acceleration) * multiplier; } } acceleration = acceleration - (entity->velocity * 0.05f); Vector2 new_velocity = (acceleration * timestep) + entity->velocity; Vector2 new_position = (acceleration * 0.5f * timestep * timestep) + (new_velocity * timestep) + GetCenter(entity->bounds); Rect2 collision_box = RectPosSize(new_position.x, new_position.y, GetWidth(entity->bounds), GetHeight(entity->bounds)); bool intersects = false; for(int j = 0; j < entities.count; j++) { if(j != i) { Entity *other_entity = entities.entities + j; intersects = intersects || Intersect(other_entity->bounds, collision_box); } } if(!intersects) { entity->velocity = new_velocity; entity->bounds = RectPosSize(new_position.x, new_position.y, GetWidth(entity->bounds), GetHeight(entity->bounds)); } else { entity->velocity = V2(0, 0); } switch(entity->type) { case EntityType_Box: { DrawRectangle(entity->bounds.min.x, entity->bounds.min.y, GetWidth(entity->bounds), GetHeight(entity->bounds), backbuffer, V4(1.0f, 0.0f, 0.0f, 1.0f)); } break; case EntityType_Player: { float angle = GetAngle(entity->velocity); Direction direction = AngleToDirection(angle); Vector4 color = V4(1.0f, 1.0f, 1.0f, 0.0f); if(direction == Direction_Up) { color = V4(1.0f, 0.0f, 0.0f, 1.0f); } else if(direction == Direction_Down) { color = V4(1.0f, 1.0f, 0.0f, 1.0f); } else if(direction == Direction_Left) { color = V4(0.0f, 1.0f, 1.0f, 1.0f); } else if(direction == Direction_Right) { color = V4(0.0f, 1.0f, 0.0f, 1.0f); } char output[255]; sprintf(output, "%f\n", angle); OutputDebugStringA(output); DrawRectangle(300, 300, 10, 10, backbuffer, color); DrawRectangle(entity->bounds.min.x, entity->bounds.min.y, GetWidth(entity->bounds), GetHeight(entity->bounds), backbuffer, intersects ? V4(0.5f, 0.0f, 0.0f, 0.5f) : V4(0.5f, 0.5f, 0.5f, 0.5f)); DrawBitmap(entity->bounds.min.x, entity->bounds.min.y, GetWidth(entity->bounds), GetHeight(entity->bounds), backbuffer, player_head); } break; } } } StretchDIBits(window_context, 0, 0, backbuffer.width, backbuffer.height, 0, 0, backbuffer.width, backbuffer.height, backbuffer.pixels, &bitmap_info, DIB_RGB_COLORS, SRCCOPY); } return 0; }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// HRESULT CAdActor::ScCallMethod(CScScript* Script, CScStack *Stack, CScStack *ThisStack, char *Name) { ////////////////////////////////////////////////////////////////////////// // GoTo / GoToAsync ////////////////////////////////////////////////////////////////////////// if(strcmp(Name, "GoTo")==0 || strcmp(Name, "GoToAsync")==0) { Stack->CorrectParams(2); int X = Stack->Pop()->GetInt(); int Y = Stack->Pop()->GetInt(); GoTo(X, Y); if(strcmp(Name, "GoToAsync")!=0) Script->WaitForExclusive(this); Stack->PushNULL(); return S_OK; } ////////////////////////////////////////////////////////////////////////// // GoToObject / GoToObjectAsync ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "GoToObject")==0 || strcmp(Name, "GoToObjectAsync")==0) { Stack->CorrectParams(1); CScValue* Val = Stack->Pop(); if(!Val->IsNative()) { Script->RuntimeError("actor.%s method accepts an entity refrence only", Name); Stack->PushNULL(); return S_OK; } CAdObject* Obj = (CAdObject*)Val->GetNative(); if(!Obj || Obj->m_Type != OBJECT_ENTITY) { Script->RuntimeError("actor.%s method accepts an entity refrence only", Name); Stack->PushNULL(); return S_OK; } CAdEntity* Ent = (CAdEntity*)Obj; if(Ent->m_WalkToX==0 && Ent->m_WalkToY==0) GoTo(Ent->m_PosX, Ent->m_PosY); else GoTo(Ent->m_WalkToX, Ent->m_WalkToY, Ent->m_WalkToDir); if(strcmp(Name, "GoToObjectAsync")!=0) Script->WaitForExclusive(this); Stack->PushNULL(); return S_OK; } ////////////////////////////////////////////////////////////////////////// // TurnTo / TurnToAsync ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "TurnTo")==0 || strcmp(Name, "TurnToAsync")==0) { Stack->CorrectParams(1); int dir; CScValue* val = Stack->Pop(); // turn to object? if(val->IsNative() && Game->ValidObject((CBObject*)val->GetNative())) { CBObject* obj = (CBObject*)val->GetNative(); int angle = (int)(atan2((double)(obj->m_PosY - m_PosY), (double)(obj->m_PosX - m_PosX)) * (180/3.14)); dir = (int)AngleToDirection(angle); } // otherwise turn to direction else dir = val->GetInt(); if(dir >= 0 && dir < NUM_DIRECTIONS) { TurnTo((TDirection)dir); if(strcmp(Name, "TurnToAsync")!=0) Script->WaitForExclusive(this); } Stack->PushNULL(); return S_OK; } ////////////////////////////////////////////////////////////////////////// // IsWalking ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "IsWalking")==0) { Stack->CorrectParams(0); Stack->PushBool(m_State==STATE_FOLLOWING_PATH); return S_OK; } ////////////////////////////////////////////////////////////////////////// // MergeAnims ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "MergeAnims")==0) { Stack->CorrectParams(1); Stack->PushBool(SUCCEEDED(MergeAnims(Stack->Pop()->GetString()))); return S_OK; } ////////////////////////////////////////////////////////////////////////// // UnloadAnim ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "UnloadAnim")==0) { Stack->CorrectParams(1); char* AnimName = Stack->Pop()->GetString(); bool Found = false; for(int i=0; i<m_Anims.GetSize(); i++) { if(stricmp(m_Anims[i]->m_Name, AnimName)==0) { // invalidate sprites in use if(m_Anims[i]->ContainsSprite(m_TempSprite2)) m_TempSprite2 = NULL; if(m_Anims[i]->ContainsSprite(m_CurrentSprite)) m_CurrentSprite = NULL; if(m_Anims[i]->ContainsSprite(m_AnimSprite2)) m_AnimSprite2 = NULL; SAFE_DELETE(m_Anims[i]); m_Anims.RemoveAt(i); i--; Found = true; } } Stack->PushBool(Found); return S_OK; } ////////////////////////////////////////////////////////////////////////// // HasAnim ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "HasAnim")==0) { Stack->CorrectParams(1); char* AnimName = Stack->Pop()->GetString(); Stack->PushBool(GetAnimByName(AnimName) != NULL); return S_OK; } else return CAdTalkHolder::ScCallMethod(Script, Stack, ThisStack, Name); }