Example #1
0
func fireDoLine(c *cmwc.Cmwc, pos linear.Vec2, angle, stored float64, speed int, level *game.Level) fireExplosion {
	rng := rand.New(c)
	ray := (linear.Vec2{1, 0})
	// ray.Scale(math.Abs(rng.NormFloat64()/10) + 50)
	scale := (stored/5 + 50) * (1 + rng.Float64()*(0.2+stored/2000))
	ray = ray.Rotate(angle).Rotate(rng.NormFloat64() * (0.2 + stored/7500)).Scale(scale)
	seg := linear.Seg2{pos, pos.Add(ray)}
	base.DoOrdered(level.Room.Walls, func(a, b string) bool { return a < b }, func(_ string, poly linear.Poly) {
		for i := range poly {
			if seg.DoesIsect(poly.Seg(i)) {
				isect := seg.Isect(poly.Seg(i))
				seg.Q = isect
			}
		}
	})
	p1 := rng.Intn(speed)
	p2 := rng.Intn(speed)
	p3 := rng.Intn(speed)
	return fireExplosion{
		Pos:    seg.Q,
		Radius: rng.Float64()*40 + 30,
		Timer:  0,
		Start:  1*speed + p1,
		Peak:   4*speed + p1 + p2,
		End:    5*speed + p1 + p2 + p3,
	}
}
Example #2
0
func (p *lightningBoltProc) Think(g *game.Game) {
	p.NumThinks++
	if p.NumThinks < p.BuildThinks {
		return
	}
	perp := p.Seg.Ray().Cross().Norm().Scale(p.Width / 2)
	for _, ent := range g.Ents {
		entSeg := linear.Seg2{
			ent.Pos().Sub(perp),
			ent.Pos().Add(perp),
		}
		if entSeg.DoesIsect(p.Seg) {
			ent.Stats().ApplyDamage(stats.Damage{stats.DamageFire, p.Dps * p.Power})
		}
	}
	// for _, ent := range g.Ents {
	// 	if ent.Pos().Sub(p.Pos).Mag2() <= p.CurrentRadius*p.CurrentRadius {
	// 		ent.Stats().ApplyDamage(stats.Damage{stats.DamageFire, p.Dps})
	// 	}
	// }
}
Example #3
0
func GenerateRoom(dx, dy, radius float64, grid int, seed int64) Room {
	var room Room
	room.Walls = make(map[string]linear.Poly)
	nextIdInt = 0
	room.Dx = int(dx)
	room.Dy = int(dy)
	c := cmwc.MakeGoodCmwc()
	if seed == 0 {
		c.SeedWithDevRand()
		n := c.Int63()
		c = cmwc.MakeGoodCmwc()
		base.Log().Printf("SEED: %v", n)
		c.Seed(n)
	} else {
		c.Seed(seed)
	}
	sanity := int(math.Sqrt(dx * dy))
	r := rand.New(c)
	var poss []linear.Vec2
	for sanity > 0 {
		pos := linear.Vec2{r.Float64() * (dx - radius + 1), r.Float64() * (dy - radius + 1)}
		good := true
		for _, p := range poss {
			if p.Sub(pos).Mag() < 2*(2*radius) {
				good = false
				break
			}
		}
		if !good {
			sanity--
			continue
		}
		poss = append(poss, pos)
	}

	// Find the pair of points that maximizes distance
	maxDist := 0.0
	for i := range poss {
		for j := range poss {
			dist := poss[i].Sub(poss[j]).Mag()
			if dist > maxDist {
				maxDist = dist
			}
		}
	}
	var a, b int
	minDist := maxDist * 3 / 4
	hits := 1.0
	for i := range poss {
		for j := range poss {
			if i == j {
				continue
			}
			dist := poss[i].Sub(poss[j]).Mag()
			if dist > minDist && r.Float64() < 1.0/hits {
				a, b = i, j
				hits = hits + 1
			}
		}
	}

	room.Starts = []linear.Vec2{poss[a], poss[b]}
	for _, start := range room.Starts {
		var data mobaRoomSideData
		data.Base = start
		room.Moba.SideData = append(room.Moba.SideData, data)
	}
	var data mobaRoomSideData
	for i, pos := range poss {
		if i == a || i == b {
			continue
		}
		data.Towers = append(data.Towers, pos)
	}
	room.Moba.SideData = append(room.Moba.SideData, data)

	sanity = int(math.Pow(dx*dy, 0.20))
	var segs []linear.Seg2
	for sanity > 0 {
		a := linear.Vec2{r.Float64() * (dx), r.Float64() * (dy)}
		length := gridify(r.Float64()*radius+(radius), grid)
		angle := float64(r.Intn(4)) * 3.1415926535 / 2
		ray := (linear.Vec2{1, 0}).Rotate(angle)
		seg := linear.Seg2{a, a.Add(ray.Scale(length))}
		seg.P.X = gridify(seg.P.X, grid)
		seg.P.Y = gridify(seg.P.Y, grid)
		seg.Q.X = gridify(seg.Q.X, grid)
		seg.Q.Y = gridify(seg.Q.Y, grid)
		good := true
		if seg.P.X <= 0 || seg.P.X >= dx || seg.P.Y <= 0 || seg.P.Y >= dy {
			good = false
		}
		if seg.Q.X <= 0 || seg.Q.X >= dx || seg.Q.Y <= 0 || seg.Q.Y >= dy {
			good = false
		}
		if seg.P.X == seg.Q.X && seg.P.Y == seg.Q.Y {
			good = false
		}
		// Can't get too close to a circle
		for _, p := range poss {
			if distFromPointToSeg(p, seg) < radius/2 {
				good = false
				break
			}
		}

		// Check to make sure this segment isn't coincident with any othe segment.
		// To avoid annoying degeneracies we'll rotate the segment slightly.
		rot := linear.Seg2{seg.P, seg.Ray().Rotate(0.01).Add(seg.P)}
		for _, cur := range segs {
			if rot.DoesIsect(cur) {
				good = false
				break
			}
		}

		if !good {
			sanity--
			continue
		}
		segs = append(segs, seg)
	}

	for _, s := range segs {
		right := s.Ray().Cross().Norm().Scale(-float64(grid))
		s2 := linear.Seg2{s.Q.Add(right), s.P.Add(right)}
		room.Walls[nextId()] = linear.Poly{s.P, s.Q, s2.P, s2.Q}
	}
	room.Walls[nextId()] = linear.Poly{
		linear.Vec2{0, 0},
		linear.Vec2{dx, 0},
		linear.Vec2{dx, dy},
		linear.Vec2{0, dy},
	}
	room.NextId = nextIdInt
	return room
}
Example #4
0
func (b *BaseEnt) Think(g *Game) {
	// This will clear out old conditions
	b.StatsInst.Think()

	var dead []int
	// Calling DoOrdered is too slow, so we just sort the Gids ourselves and go
	// through them in order.
	pids := make([]int, len(b.Processes))[0:0]
	for pid := range b.Processes {
		pids = append(pids, pid)
	}
	sort.Ints(pids)
	for _, pid := range pids {
		proc := b.Processes[pid]
		proc.Think(g)
		if proc.Dead() {
			dead = append(dead, pid)
		} else {
			b.StatsInst.ApplyCondition(proc)
		}
	}

	// Removed dead processes from the ent
	for _, id := range dead {
		delete(b.Processes, id)
	}

	if b.Delta.Speed < -1.0 {
		b.Delta.Speed = -1.0
	}
	if b.Delta.Speed > 1.0 {
		b.Delta.Speed = 1.0
	}

	// TODO: Speed is a complete misnomer now - fix it!
	force := b.Delta.Speed * (linear.Vec2{1, 0}).Rotate(b.Target.Angle).Dot((linear.Vec2{1, 0}).Rotate(b.Angle_))
	b.ApplyForce((linear.Vec2{1, 0}).Rotate(b.Angle_).Scale(force * b.Stats().MaxAcc()))

	mangle := math.Atan2(b.Velocity.Y, b.Velocity.X)
	friction := g.Friction
	b.Velocity = b.Velocity.Scale(
		math.Pow(friction, 1+3*math.Abs(math.Sin(b.Angle_-mangle))))

	if b.Velocity.Mag2() < 0.01 {
		b.Velocity = linear.Vec2{0, 0}
	} else {
		size := b.Stats().Size()
		sizeSq := size * size
		// We pretend that the player is started from a little behind wherever they
		// actually are.  This makes it a lot easier to get collisions to make sense
		// from frame to frame.
		epsilon := b.Velocity.Norm().Scale(size / 2)
		move := linear.Seg2{b.Position.Sub(epsilon), b.Position.Add(b.Velocity)}
		prev := b.Position
		walls := g.local.temp.WallCache.GetWalls(int(b.Position.X), int(b.Position.Y))
		for _, wall := range walls {
			// Don't bother with back-facing segments
			if wall.Right(b.Position) {
				continue
			}

			// Check against the segment itself
			if wall.Ray().Cross().Dot(move.Ray()) <= 0 {
				shiftNorm := wall.Ray().Cross().Norm()
				shift := shiftNorm.Scale(size)
				col := linear.Seg2{shift.Add(wall.P), shift.Add(wall.Q)}
				if move.DoesIsect(col) {
					cross := col.Ray().Cross()
					fix := linear.Seg2{move.Q, cross.Add(move.Q)}
					isect := fix.Isect(col)
					move.Q = isect
				}
			}
		}
		for _, wall := range walls {
			// Check against the leading vertex
			{
				v := wall.P
				originMove := linear.Seg2{move.P.Sub(v), move.Q.Sub(v)}
				originPerp := linear.Seg2{linear.Vec2{}, move.Ray().Cross()}
				dist := originMove.DistFromOrigin()
				if originPerp.DoesIsect(originMove) && dist < size {
					// Stop passthrough
					isect := originMove.Isect(originPerp).Add(v)
					diff := math.Sqrt(sizeSq - dist*dist)
					finalLength := isect.Sub(move.P).Mag() - diff
					move.Q = move.Ray().Norm().Scale(finalLength).Add(move.P)
				} else if v.Sub(move.Q).Mag2() < sizeSq {
					move.Q = move.Q.Sub(v).Norm().Scale(size).Add(v)
				}
			}
		}
		b.Position = move.Q
		b.Velocity = b.Position.Sub(prev)
	}

	if math.Abs(b.Angle_+b.Target.Angle-math.Pi) < 0.01 {
		b.Angle_ += 0.1
	} else {
		frac := 0.80
		curDir := (linear.Vec2{1, 0}).Rotate(b.Angle_).Scale(frac)
		targetDir := (linear.Vec2{1, 0}).Rotate(b.Target.Angle).Scale(1.0 - frac)
		newDir := curDir.Add(targetDir)
		if newDir.Mag() > 0.01 {
			b.Angle_ = newDir.Angle()
		}
	}
}