void SkeletalCreature::render(Surface *renderer, int xoffset, int yoffset) { bool mirror_body_parts = (world.variables["engine_mirror_creature_body_parts"] == 1); for (int j = 0; j < 17; j++) { int i = cee_zorder[posedirection][j]; if (i >= SkeletalPartCount()) continue; // CV hackery if (engine.version == 1) // TODO: this is hackery to skip tails for C1 if (i == 6 || i == 13) continue; bodypartinfo *part = &cee_bodyparts[i]; unsigned int ourpose = pose[i]; bool mirror = false; if (i != 14 && i != 15 && mirror_body_parts && ourpose >= 4 && ourpose <= 7) { ourpose -= 4; mirror = true; } // adjust for pregnancy/facial expressions/etc as necessary if (part->parent == -1) { // body ourpose += (pregnancy * (engine.version < 3 ? 10 : 16)); } else if (i == 1) { // head ourpose += (eyesclosed ? (engine.version < 3 ? 10 : 16) : 0) + (facialexpression * (engine.version < 3 ? 20 : 32)); } else if (i == 16) { // hair ourpose += 0; // TODO: 16 * hair } assert(images[i]); renderer->render(images[i], ourpose, partx[i] + adjustx + xoffset, party[i] + adjusty + yoffset, false, 0, mirror); if (displaycore) { // TODO: we draw a lot of points twice here :) int atx = attachmentX(i, 0) + xoffset, aty = attachmentY(i, 0) + yoffset; renderer->renderLine(atx - 1, aty, atx + 1, aty, 0xFF0000CC); renderer->renderLine(atx, aty - 1, atx, aty + 1, 0xFF0000CC); atx = attachmentX(i, 1) + xoffset; aty = attachmentY(i, 1) + yoffset; renderer->renderLine(atx - 1, aty, atx + 1, aty, 0xFF0000CC); renderer->renderLine(atx, aty - 1, atx, aty + 1, 0xFF0000CC); } } }
std::pair<int, int> SkeletalCreature::getCarryPoint() { std::pair<int, int> carrypoint; // TODO: 9 is left hand, how do we work out which hand a norn is carrying with? carrypoint.first = attachmentX(9, 1); carrypoint.second = attachmentY(9, 1); return carrypoint; }
void SkeletalCreature::setPose(std::string s) { switch (s[0]) { case '?': switch (direction) { case 0: break; // north, TODO case 1: break; // south, TODO case 2: posedirection = 0; break; // right case 3: posedirection = 1; break; // left default: assert(false); } break; case '!': switch (direction) { case 0: break; // north, TODO case 1: break; // south, TODO case 2: posedirection = 1; break; // right case 3: posedirection = 0; break; // left default: assert(false); } break; case '0': posedirection = 3; break; case '1': posedirection = 2; break; case '2': posedirection = 0; break; case '3': posedirection = 1; break; case 'X': break; // do nothing default: std::cout << "internal warning: SkeletalCreature::setPose didn't understand direction " << s[0] << " in pose '" << s << "'." << std::endl; break; } for (int i = 0; i < 14; i++) { int newpose; switch (s[i + 1]) { case '0': newpose = 0 + (posedirection * 4); break; case '1': newpose = 1 + (posedirection * 4); break; case '2': newpose = 2 + (posedirection * 4); break; case '3': newpose = 3 + (posedirection * 4); break; case '?': assert(i == 0); { // make the head look in the posedirection of _IT_ float attachmenty = attachmentY(1, 0) + y; // head attachment point, which we'll use to 'look' from atm // TODO: this is horrible, but i have no idea how the head angle is calculated AgentRef attention = creature->getAttentionFocus(); if (attention && attention->y > (attachmenty + 30)) newpose = 0; else if (attention && attention->y < (attachmenty - 70)) newpose = 3; else if (attention && attention->y < (attachmenty - 30)) newpose = 2; else newpose = 1; newpose += (posedirection * 4); } break; // TODO: '!' also? case 'X': continue; // do nothing default: std::cout << "internal warning: SkeletalCreature::setPose didn't understand " << s[i + 1] << " in pose '" << s << "'." << std::endl; continue; } pose[cee_lookup[i]] = newpose; // TODO: this is some hackery for CV, if (world.gametype != "cv") continue; if (i == 0) { // head pose[14] = newpose; pose[15] = newpose; // ears pose[16] = newpose; // hair } else if (i == 1) { pose[6] = newpose; // tail root pose[13] = newpose; // tail tip } } recalculateSkeleton(); }
void SkeletalCreature::snapDownFoot() { // TODO: this isn't very well thought-out. int orig_footpart = (downfoot_left ? 11 : 12); float footx = x + attachmentX(orig_footpart, 1); float footy = y + attachmentY(orig_footpart, 1); MetaRoom *m = world.map.metaRoomAt(x, y); if (!m) return; // TODO: exceptiony death shared_ptr<Room> newroom; if (downfootroom) { if (downfootroom->containsPoint(footx, footy)) { newroom = downfootroom; } else { if (downfootroom->x_left <= footx && downfootroom->x_right >= footx) { newroom = downfootroom; // TODO, we're just forcing for now } else { float ydiff = 10000.0f; // TODO: big number for (std::map<weak_ptr<Room>,RoomDoor *>::iterator i = downfootroom->doors.begin(); i != downfootroom->doors.end(); i++) { shared_ptr<Room> thisroom = i->first.lock(); if (engine.version == 2 && size.getInt() > i->second->perm) continue; if (thisroom->x_left <= footx && thisroom->x_right >= footx) { float thisydiff = fabs(footy - thisroom->floorYatX(footx)); if (thisydiff < ydiff) { newroom = thisroom; ydiff = thisydiff; } } } } } } else { newroom = bestRoomAt(footx, footy, 3, m, shared_ptr<Room>()); // insane emergency handling float newfooty = footy; while (!newroom && newfooty > (footy - 500.0f)) { newroom = m->roomAt(footx, newfooty); newfooty--; } // TODO: give up here footy = newfooty; } bool newroomchosen = (newroom != downfootroom) && downfootroom; bool hadroom = (downfootroom); downfootroom = newroom; if (!downfootroom /*|| !falling */) { // TODO: hackery to cope with scripts moving us, this needs handling correctly somewhere if (fabs(lastgoodfootx - attachmentX(orig_footpart, 1) - x) > 50.0f || fabs(lastgoodfooty - attachmentY(orig_footpart, 1) - y) > 50.0f) { downfootroom = bestRoomAt(footx, footy, 3, m, shared_ptr<Room>()); if (downfootroom) { snapDownFoot(); return; } else { std::cout << "Creature out of room system at (" << footx << ", " << footy << ")!" << std::endl; // TODO: exceptiony death? return; } } // We fell out of the room system! How did that happen? Push ourselves back in, run collision script. std::cout << "Creature out of room system at (" << footx << ", " << footy << "), pushing it back in." << std::endl; // TODO: sucky code x = lastgoodfootx - attachmentX(orig_footpart, 1); footx = lastgoodfootx; footy = lastgoodfooty; downfootroom = m->roomAt(footx, footy); queueScript(6); if (!downfootroom) { std::cout << "no down foot room! (" << footx << ", " << footy << ")" << std::endl; // TODO: exceptiony death return; } } bool belowfloor = false; float newy = downfootroom->floorYatX(footx); if (engine.version == 2 && hadroom && y > newy) { // TODO: hilar hack: cope with walking below floors belowfloor = true; newy = downfootroom->bot.pointAtX(footx).y; } if (engine.version > 1) { // TODO: hilar hack: enable gravity if we're snapping by much if (newroomchosen && abs(y - (newy - (footy - y))) > 20) { falling = true; return; } } moveTo(x, newy - (footy - y)); lastgoodfootx = footx; lastgoodfooty = footy; if (engine.version > 2) { if (engine.version == 2 && !belowfloor && downfootroom->floorpoints.size()) { // TODO: hilar hack: same as above for floorvalue if (size.getInt() <= downfootroom->floorvalue.getInt()) { falling = true; return; } } else { // TODO: hilar hack: same as above for perm shared_ptr<Room> downroom = world.map.roomAt(footx, downfootroom->y_left_floor + 1); if (downfootroom->doors.find(downroom) != downfootroom->doors.end()) { int permsize = (engine.version == 2 ? size.getInt() : perm); if (permsize <= downfootroom->doors[downroom]->perm) { falling = true; return; } } } } }
void SkeletalCreature::recalculateSkeleton() { int lowestx = 0, lowesty = 0, highestx = 0, highesty = 0; for (int i = 0; i < SkeletalPartCount(); i++) { if (engine.version == 1) // TODO: this is hackery to skip tails for C1 if (i == 6 || i == 13) continue; bodypartinfo *part = &cee_bodyparts[i]; if (part->parent == -1) { partx[i] = 0; party[i] = 0; } else { attFile &bodyattinfo = att[0]; attFile &attinfo = att[i]; int attachx = att[i].attachments[pose[i]][0]; int attachy = att[i].attachments[pose[i]][1]; int x, y; if (part->parent == 0) { // linking to body x = bodyattinfo.attachments[pose[0]][part->attorder * 2]; y = bodyattinfo.attachments[pose[0]][(part->attorder * 2) + 1]; } else { // extra limb attFile &parentattinfo = att[part->parent]; x = partx[part->parent] + parentattinfo.attachments[pose[part->parent]][part->attorder * 2]; y = party[part->parent] + parentattinfo.attachments[pose[part->parent]][(part->attorder * 2) + 1]; } x = x - attachx; y = y - attachy; partx[i] = x; party[i] = y; if (x < lowestx) { lowestx = x; } if (y < lowesty) { lowesty = y; } if (x + (int)images[i]->width(pose[i]) > highestx) { highestx = x + images[i]->width(pose[i]); } if (y + (int)images[i]->height(pose[i]) > highesty) { highesty = y + images[i]->height(pose[i]); } } } adjustx = -lowestx; adjusty = -lowesty; // TODO: muh, we should cooperate with physics system etc if (!carriedby && !invehicle && calculated) { int orig_footpart = (downfoot_left ? 11 : 12); // adjust location to match foot moveTo(x - (attachmentX(orig_footpart, 1) - oldfootx), y - (attachmentY(orig_footpart, 1) - oldfooty)); } // work out which foot is down int leftfoot = attachmentY(11, 1); int rightfoot = attachmentY(12, 1); downfoot_left = (rightfoot < leftfoot); calculated = true; int orig_footpart = (downfoot_left ? 11 : 12); oldfootx = attachmentX(orig_footpart, 1); oldfooty = attachmentY(orig_footpart, 1); // recalculate width/height height = downfoot_left ? leftfoot : rightfoot; width = 50; // TODO: arbitary values bad // TODO: muh, we should cooperate with physics system etc /*if (carriedby || invehicle) downfootroom.reset(); else snapDownFoot();*/ }
void SkeletalCreature::setPose(std::string s) { switch (s[0]) { case '?': // towards object of attention switch (direction) { case 0: posedirection = 3; break; // north, TODO case 1: posedirection = 2; break; // south, TODO case 2: posedirection = 0; break; // right case 3: posedirection = 1; break; // left default: assert(false); } break; case '!': // away from object of attention switch (direction) { case 0: posedirection = 2; break; // north, TODO case 1: posedirection = 3; break; // south, TODO case 2: posedirection = 1; break; // right case 3: posedirection = 0; break; // left default: assert(false); } break; case '0': posedirection = 3; break; case '1': posedirection = 2; break; case '2': posedirection = 0; break; case '3': posedirection = 1; break; case 'X': break; // do nothing default: std::cout << "internal warning: SkeletalCreature::setPose didn't understand direction " << s[0] << " in pose '" << s << "'." << std::endl; break; } for (int i = 0; i < 14; i++) { int newpose = -1; switch (s[i + 1]) { case '0': newpose = 0; break; case '1': newpose = 1; break; case '2': newpose = 2; break; case '3': newpose = 3; break; case '4': newpose = (engine.version < 3) ? 8 : 10; break; // 'to camera' case '?': assert(i == 0); { // TODO // make the head look in the posedirection of _IT_ float attachmenty = attachmentY(1, 0) + y; // head attachment point, which we'll use to 'look' from atm // TODO: this is horrible, but i have no idea how the head angle is calculated AgentRef attention = creature->getAttentionFocus(); if (attention && attention->y > (attachmenty + 30)) newpose = 0; else if (attention && attention->y < (attachmenty - 70)) newpose = 3; else if (attention && attention->y < (attachmenty - 30)) newpose = 2; else newpose = 1; } break; // TODO: '!' also? case 'X': continue; // do nothing default: std::cout << "internal warning: SkeletalCreature::setPose didn't understand " << s[i + 1] << " in pose '" << s << "'." << std::endl; continue; } assert(newpose != -1); if (newpose < 4) { // newpose gives the angle, now we need to add the offset for left/right/forward/back. if (engine.version < 3 && posedirection > 1) newpose = 6 + posedirection; // only one forward/back pose in c1/c2 else newpose += (posedirection * 4); } pose[cee_lookup[i]] = newpose; // TODO: this is some hackery for CV, if (world.gametype != "cv") continue; if (i == 0) { // head pose[14] = newpose; pose[15] = newpose; // ears pose[16] = newpose; // hair } else if (i == 1) { pose[6] = newpose; // tail root pose[13] = newpose; // tail tip } } recalculateSkeleton(); }