/* ====================== = = HuffExpand = ====================== */ public static void HuffExpand(byte[] sourceBuffer, int sourceIndex, byte[] destBuffer, int destIndex, int length, huffnode hufftable) { memptr source = new memptr(sourceBuffer, sourceIndex); memptr dest = new memptr(destBuffer, destIndex); ushort bit, _byte, code; huffnode nodeon, headptr; headptr = new huffnode(hufftable, 254); // head node is allways node 254 // as: The disabled C code that was in this function appears to be the C version of the asm code // this came in handy during the conversion nodeon = new huffnode(headptr); // as: bugfix - refactored to prevent the out of bounds read that can occur occasionally with the final byte bit = 256; _byte = 0; while(length != 0) { if(bit == 256) { bit = 1; _byte = source.GetUInt8(0); source.Offset(1); } if((_byte & bit) != 0) code = nodeon.bit1; else code = nodeon.bit0; bit <<= 1; if(code < 256) { dest.SetUInt8(0, (byte) code); dest.Offset(1); nodeon = headptr; length--; } else { nodeon = new huffnode(hufftable, code - 256); } } }
public static void RLEWExpand(memptr source, memptr dest) { int length = source.GetInt32(0); memptr end = new memptr(dest, length); source.Offset(4); // skip length words // // expand it // do { ushort value = source.GetUInt16(0); source.Offset(2); if(value != RLETAG) { // // uncompressed // dest.SetUInt16(0, value); dest.Offset(2); } else { // // compressed string // ushort count = source.GetUInt16(0); source.Offset(2); value = source.GetUInt16(0); source.Offset(2); if(dest.BaseIndex + count * 2 > end.BaseIndex) throw new Exception("RLEWExpand error!"); for(ushort i = 1; i <= count; i++) { dest.SetUInt16(0, value); dest.Offset(2); } } } while(dest.BaseIndex < end.BaseIndex); }
//========================================================================== ///////////////////////////////////////////////////////// // // InitGrFile // ///////////////////////////////////////////////////////// private void InitGrFile() { // // calculate some offsets in the header // grhuffman = new huffnode(grhead); grstarts = new memptr(grhead.Buffer, grhead.dataoffsets); OptimizeNodes(grhuffman); // // Open the graphics file, leaving it open until the game is finished // grhandle = _sys.open("EGAGRAPH." + EXTENSION); if(grhandle.IsNull) Quit("Cannot open EGAGRAPH." + EXTENSION + "!"); memptr buffer = new memptr(); // // load the pic and sprite headers into the data segment // needgr[STRUCTPIC] = 1; // make sure this chunk never reloads grsegs[STRUCTPIC] = new memptr(null, 0xffff); GetChunkLength(STRUCTPIC); // position file pointer MMGetPtr(ref buffer, chunkcomplen); SegRead(ref grhandle, buffer, chunkcomplen); // as: Added temp pointer memptr temp = new memptr(new byte[pictable.Length * pictype.SizeOf], 0); HuffExpand(buffer.Buffer, buffer.BaseIndex, temp.Buffer, 0, temp.Buffer.Length, grhuffman); // as: Initialise pictypes for(int i = 0; i < pictable.Length; i++) { pictable[i] = new pictype(temp); temp.Offset(pictype.SizeOf); } MMFreePtr(ref buffer); }
private void SaveCtrls() { memptr handle = new memptr(new byte[key.Length + 2 + 4 + 2]); for(int i = 0; i < key.Length; i++) handle.SetInt8(i, key[i]); handle.Offset(key.Length); handle.SetInt8(0, keyB1); handle.Offset(1); handle.SetInt8(0, keyB2); handle.Offset(1); handle.SetInt32(0, highscore); handle.Offset(4); handle.SetInt16(0, bestlevel); handle.Offset(2); _sys.SaveControls(handle); // as: Handled separately now }
//========================================================================== /* ========================== = = SegRead = = Read from a file to a segment pointer = ========================== */ private void SegRead(ref memptr handle, memptr dest, int length) { if(length > 0xffff) Quit("SegRead doesn't support 64K reads yet!"); Array.Copy(handle.Buffer, handle.BaseIndex, dest.Buffer, dest.BaseIndex, length); handle.Offset(length); }
/// <summary>Returns a byte array containing 16-bit signed samples for the specified speaker sound.</summary> /// <param name="speakerSound">The speaker sound.</param> /// <param name="soundsPointer">The speaker sounds pointer.</param> /// <param name="sampleFrequency">The sample frequency in Hz.</param> /// <param name="amplitude">The peak amplitude (0 to 1).</param> /// <returns>A byte array.</returns> public static byte[] GetSpeakerSamplesS16(spksndtype speakerSound, memptr soundsPointer, double sampleFrequency, double amplitude) { soundsPointer.Offset(speakerSound.start); PCSpeaker pcSpeaker = new PCSpeaker(sampleFrequency, amplitude); // as: Added checks to catch problems with SOUNDS.HOV files (Demon Hunter v1.1): // Also, the maximum sample time has been limited to 10s // and: sound generation stops if the end of the soundsPointer buffer is reached double time = 1.0 / spksndtype.Frequency(0x2147); ushort timerValue = soundsPointer.GetUInt16(0); double maxTime = 10.0; while(timerValue != spksndtype.SpeakerData_EndSound) { pcSpeaker.SetTimer((ushort) timerValue); pcSpeaker.WriteSamples(time); soundsPointer.Offset(2); if(soundsPointer.BaseIndex + 1 >= soundsPointer.Buffer.Length) break; timerValue = soundsPointer.GetUInt16(0); if(pcSpeaker.ElapsedTime > maxTime) break; } return pcSpeaker.ToArray(); }
public scaleseg(memptr pointer, ushort offset) { _pointer = pointer; _pointer.Offset(offset); }
/* =========================== = = MakeShape = = Takes a raw bit map of width bytes by height and creates a scaleable shape = = Returns the length of the shape in bytes = =========================== */ private void SC_MakeShape(memptr src, short width, short height, ref memptr shapeseg) { short pixwidth = (short) (width * 8); memptr tempseg_memptr = new memptr(); // as: added MMGetPtr(ref tempseg_memptr, pixwidth * (height + 20)); // larger than needed buffer scaleshape tempseg = new scaleshape(tempseg_memptr); tempseg.width = pixwidth; // pixel dimensions tempseg.height = height; // // convert ega pixels to byte color values in a temp buffer // // Stored in a collumn format, not rows! // memptr byteseg = new memptr(); MMGetPtr(ref byteseg, pixwidth * height); memptr byteptr = new memptr(byteseg); memptr plane0 = new memptr(src); memptr plane1 = new memptr(plane0, width * height); memptr plane2 = new memptr(plane1, width * height); memptr plane3 = new memptr(plane2, width * height); for(short x = 0; x < width; x++) { for(ushort b = 0; b < 8; b++) { ushort shift = (ushort) (8 - b); ushort offset = (ushort) x; for(short y = 0; y < height; y++) { byte by0 = plane0.GetUInt8(offset); byte by1 = plane1.GetUInt8(offset); byte by2 = plane2.GetUInt8(offset); byte by3 = plane3.GetUInt8(offset); offset += (ushort) width; ushort color = 0; // as: converted from asm color |= AsmRotate(by3, shift); color <<= 1; color |= AsmRotate(by2, shift); color <<= 1; color |= AsmRotate(by1, shift); color <<= 1; color |= AsmRotate(by0, shift); byteptr.SetUInt8(0, (byte) color); byteptr.Offset(1); } // Y } // B } // X // // convert byte map to sparse scaling format // memptr saveptr = tempseg.PointerTofirst(pixwidth); // start filling in data after all pointers to line segments byteptr = new memptr(byteseg); // first pixel in byte array for(short x = 0; x < pixwidth; x++) { // // each vertical line can have 0 or more segments of pixels in it // short y = 0; memptr segptr = tempseg.PointerTofirst(x); segptr.SetUInt16(0, 0); // in case there are no segments on line do { // scan for first pixel to be scaled while(y < height && byteptr.GetUInt8(0) == BACKGROUND) // as: bugfix - re-ordered to prevent out of bounds read { byteptr.Offset(1); y++; } if(y == height) // if not, the line is finished continue; // // start a segment by pointing the last link (either shape.first[x] if it // is the first segment, or a seg.next if not) to the current spot in // the tempseg, setting segptr to this segments next link, and copying // all the pixels in the segment // segptr.SetUInt16(0, _sys.FP_OFF(saveptr)); // pointer to start of this segment short start = y; short length = 0; scaleseg scale_seg = new scaleseg(saveptr); memptr dataptr = scale_seg.PointerToData(0); // // copy bytes in the segment to the shape // while(y < height && byteptr.GetUInt8(0) != BACKGROUND) // as: bugfix - re-ordered to prevent out of bounds read { length++; dataptr.SetUInt8(0, byteptr.GetUInt8(0)); dataptr.Offset(1); byteptr.Offset(1); y++; } scale_seg.start = start; scale_seg.length = length; scale_seg.next = 0; // get ready for next segment segptr = new memptr(saveptr, scaleseg.FieldOffset_next); saveptr = dataptr; // next free byte to be used } while(y < height); } // // allocate exact space needed and copy shape to it, then free buffers // MMGetPtr(ref shapeseg, _sys.FP_OFF(saveptr)); Array.Copy(tempseg.Pointer.Buffer, shapeseg.Buffer, _sys.FP_OFF(saveptr)); MMFreePtr(ref byteseg); MMFreePtr(ref tempseg_memptr); }
//========================================================================== /* ================== = = StartLevel = ================== */ private void StartLevel(memptr plane1) { numrefugees = 0; // as: Enemy stats enemiesKilled = 0; totalEnemies = 0; for(ushort y = 0; y < levelheader.height; y++) { for(ushort x = 0; x < levelheader.width; x++) { ushort tile = plane1.GetUInt16(0); plane1.Offset(2); if(tile > 0) { ushort dir = (ushort) (tile >> 8); // high byte gives starting dir tile &= 0xff; fixed_t gx = x * TILEGLOBAL + TILEGLOBAL / 2; fixed_t gy = y * TILEGLOBAL + TILEGLOBAL / 2; // as: Added LevelObjects switch(tile) { case LevelObjects.MaleRefugee: SpawnRefugee(gx, gy, true); break; case LevelObjects.Drone: SpawnDrone(gx + TILEGLOBAL / 2, gy + TILEGLOBAL / 2); break; case LevelObjects.Tank: SpawnTank(gx + TILEGLOBAL / 2, gy + TILEGLOBAL / 2); break; case LevelObjects.Mutant: SpawnMutant(gx + TILEGLOBAL / 2, gy + TILEGLOBAL / 2); break; case LevelObjects.Shield: SpawnShield(gx, gy); break; case LevelObjects.FemaleRefugee: SpawnRefugee(gx, gy, false); break; case LevelObjects.WarpGate: warpx = gx; // warp gate is spawned when all men are done warpy = gy; break; case LevelObjects.Player: SpawnPlayer(gx, gy); short angle = (short) (ANGLES / 4 - dir * ANGLES / 4); if(angle < 0) angle += ANGLES; objlist[0].angle = angle; break; } } } } totalrefugees = numrefugees; }